/**
 * All Rights Reserved , Copyright (C) 2021 , 青岛鼎信通讯股份有限公司
 * SdProjectService
 * SD项目立项
 * 修改纪录
 * 2021-11-22 版本：1.0 jiangtao 创建。
 *
 * @version 版本：1.0
 * @author 作者：jiangtao
 * 创建日期：2021-11-22
 */
package com.topscomm.gpm.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.topscomm.basic.exception.MessageException;
import com.topscomm.cbo.pojo.*;
import com.topscomm.cbo.service.*;
import com.topscomm.cbo.service.impl.CboApprovalNodeInsService;
import com.topscomm.cbo.service.impl.CboUserRoleService;
import com.topscomm.cbo.service.impl.CboUserService;
import com.topscomm.ltc.pojo.LtcContractApplyEntity;
import com.topscomm.gpm.utils.MessageUtil;
import com.topscomm.mis.constant.MisSystemConst;
import com.topscomm.mis.mobile.message.service.SendMessageService;
import com.topscomm.tap.TapEntity;
import com.topscomm.tap.common.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.topscomm.basic.exception.BusinessException;
import com.topscomm.basic.exception.ServiceException;
import com.topscomm.basic.util.SQLAdapter;
import com.topscomm.ltc.pojo.LtcContractProductInfoEntity;
import com.topscomm.ltc.service.ILtcContractProductInfoService;
import com.topscomm.main.hessian.IMpmProjectService;
import com.topscomm.mms.pojo.MmsDeptExtraInfoEntity;
import com.topscomm.mms.service.impl.MmsDeptExtraInfoService;
import com.topscomm.pub.util.*;
import com.topscomm.pub.vo.Page;
import com.topscomm.pub.vo.Query;
import com.topscomm.pub.vo.ResponseResult;
import com.topscomm.gpm.GpmSystemConst;
import com.topscomm.gpm.pojo.*;
import com.topscomm.tap.threadlocal.ThreadLocalContext;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import com.topscomm.gpm.service.IGpmProjectService;
import com.topscomm.gpm.service.impl.auto.GpmProjectServiceAuto;
import com.topscomm.basic.BasicEntity;
import com.topscomm.basic.util.PrimaryKeyUtil;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

@Service(value = "gpmProjectService")
@Scope(value = "singleton")
public class GpmProjectService extends GpmProjectServiceAuto implements IGpmProjectService {
	@Autowired
	private ILtcContractProductInfoService ltcContractProductInfoService;
	@Autowired
	private GpmWfFormService gpmWfFormService;
	@Autowired
	private MmsDeptExtraInfoService mmsDeptExtraInfoService;
	@Autowired
	private GpmProjectTaskService gpmProjectTaskService;
	@Autowired
	private GpmProjectAppointmentService gpmProjectAppointmentService;
	@Autowired
	private GpmProjectPlanService gpmProjectPlanService;
	@Autowired
	private GpmProjectMilepostService gpmProjectMilepostService;
	@Autowired
	private GpmProjectSuperviseService gpmProjectSuperviseService;
	@Autowired
	private GpmDataBoardCustomizeRecordService gpmDataBoardCustomizeRecordService;
	private static final String NULL = "null";
	@Autowired
	private GpmProjectHistoryService gpmProjectHistoryService;
	@Autowired
	private ICboApprovalFlowInsService cboApprovalFlowInsService;
	@Autowired
	private ICboMessageAppService cboMessageAppService;
	@Autowired
	private ICboMessageSysService cboMessageSysService;
	@Autowired(required = false)
	private IMpmProjectService mpmProjectService;
	@Autowired
	private ICboApprovalNodeInsService cboApprovalNodeInsService;
	@Autowired
	private FlowDatacodeCache flowDatacodeCache;
	@Autowired
	private DatacodeCache datacodeCache;
	@Autowired
	private CboUserService cboUserService;
	@Autowired
	private GpmProjectStakeholderService gpmProjectStakeholderService;
	@Autowired
	private GpmProjectProblemService gpmProjectProblemService;
	@Autowired
	private GpmProjectRiskService gpmProjectRiskService;
	@Autowired
	private GpmProjectTeamService gpmProjectTeamService;
	@Autowired
	private GpmProjectReviewService gpmProjectReviewService;
	@Autowired
	private CboUserRoleService cboUserRoleService;
	@Autowired
	private SendMessageService sendMessageService;

	private static final String PROJECTSOURCETYPE="GpmProjectInfo";

	private final Logger logger = LoggerFactory.getLogger(GpmProjectService.class);
	public static final long DAY_MILLSECONDS = 24 * 60 * 60 * 3000L;// 以毫秒为单位，这是三天的意思
	/**
	 * @author: jiangtao
	 * @date: 2021-11-22
	 * @param entity
	 * @throws
	 * @description:单号生成
	 * @modify:
	 */
	@Override
	protected void beforeInsert(BasicEntity entity) {
		super.beforeInsert(entity);
		if (entity.getId() <= 0) {// 赋值Id和单号
			long[] arrayId = PrimaryKeyUtil.GeneIDs(entity.getTableName(), 1);
			entity.setId(arrayId[0]);
			String docNo = String.valueOf(arrayId[0]);
			docNo = "GPM" + docNo.substring(0, 6) + docNo.substring(9);
			entity.setValue(GpmProjectEntity.FieldProjectcode,docNo);
		}
		// 赋值deptcommoncode1省份
		String deptcode = ConvertUtil.convertToString(entity.getValue(GpmProjectEntity.FieldDeptcode));
		String deptcommoncode1 = mmsDeptExtraInfoService.getDeptCommonCode(deptcode);
		entity.setValue(GpmProjectEntity.FieldVersion,1L);
		entity.setValue(GpmProjectEntity.FieldDeptcommoncode1,deptcommoncode1);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Map<String, Object> doSave(Map<String, Object> inputMap) {
		Map<String, Object> resultMap = new HashMap<String, Object>();
		Map<String, Object> basicInfo = (Map<String, Object>) inputMap.get("basicInfo");
		GpmProjectEntity gpmProjectEntity = new GpmProjectEntity();
		long id = 0L;
		if(basicInfo == null) {
			return resultMap;
		}
		gpmProjectEntity.convertFromMap(basicInfo);
		gpmProjectEntity = this.saveProjectInfo(gpmProjectEntity);
		id = gpmProjectEntity.getId();
		resultMap.put("id", gpmProjectEntity.getId());
		return resultMap;
	}

	/***
	 * @description: 选择来源后，赋值产品信息
	 * @param paraMap
	 * @return
	 * @author: jiangtao1
	 * @date: 2021/11/30 8:52
	 * @modify:
	 */
	@Override
	public List<Map<String, Object>> copyProductInfo(Map<String, Object> paraMap) {
		List<String> queryFields = new ArrayList<>();
		queryFields.add(LtcContractProductInfoEntity.FieldProductbigtype);
		queryFields.add(LtcContractProductInfoEntity.FieldProductline);
		queryFields.add(LtcContractProductInfoEntity.FieldProductmiddletype);
		queryFields.add(LtcContractProductInfoEntity.FieldProductsmalltype);
		queryFields.add(LtcContractProductInfoEntity.FieldOuritemname + " as productname");
		queryFields.add(LtcContractProductInfoEntity.FieldUnit);
		queryFields.add(LtcContractProductInfoEntity.FieldMoney);
		queryFields.add(LtcContractProductInfoEntity.FieldQty + " as amount");
		List<Map<String, Object>> originList = ltcContractProductInfoService
				.queryMapFieldsByWhere(LtcContractProductInfoEntity.FieldContractid + "=" + ConvertUtil.convertToString(paraMap.get("origincontractid")) + " order by id asc", queryFields);
		originList.forEach(item -> {
			item.put("id", 0);
			item.put("money",ConvertUtil.convertToBigDecimal(item.get("money")).divide(new BigDecimal("10000"), RoundingMode.HALF_UP));
			item.put("finishamount", null);
			item.put("finishmoney", null);
			item.put("projectid", 0);
			item.put("sourceid", 0);
			item.put("projectcode", null);
			item.put("description", null);
		});
		return originList;
	}

	@Override protected void doApprove(String nodeInsId, Date approvalDate, String approvalOpinion, String approvalType, String backNodeId, List<CboApprovalNodeEntity> listNodeForNonUser, SessionUserBean sessionUserBean, long nextUserId) {
		super.doApprove(nodeInsId, approvalDate, approvalOpinion, approvalType, backNodeId, listNodeForNonUser, sessionUserBean, nextUserId);
	}

	/***
	 * @description: 立项申请提交审批
	 * @param paraMap
	 * @return
	 * @author: jiangtao1
	 * @date: 2021/11/30 10:23
	 * @modify:
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void doProjectApproval(Map<String, Object> paraMap) {
		String id = ConvertUtil.convertToString(paraMap.get("id"));
		GpmProjectEntity projectEntity = this.queryById(id);
		int state = projectEntity.getState();
		if (TapSystemConst.TapApprovalNodeStateEnum.Approveing == state) {
			throw new ServiceException("该项目处于立项审核中，不允许重复提交审批");
		}
		// 生成提交实体
		GpmWfFormEntity gpmWfFormEntity = new GpmWfFormEntity();
		// 流程管理项目立项
		if (GpmSystemConst.GPM_APPROVAL_PROJECT_TYPE.GpmProcessProject.equals(projectEntity.getApprovalprojecttype())) {
			gpmWfFormEntity = gpmWfFormService.generateWfFormEntity(GpmProjectEntity.tableName,projectEntity, GpmSystemConst.SdApprovalCategory.SdProjectApproval);
		} else { // 通用管理项目立项
			gpmWfFormEntity = gpmWfFormService.generateWfFormEntity(GpmProjectEntity.tableName,projectEntity, GpmSystemConst.SdApprovalCategory.SdProjectApproval);
		}
		// 流程管理项目立项
		long flowid = 0L;
		if (GpmSystemConst.GPM_APPROVAL_PROJECT_TYPE.GpmProcessProject.equals(projectEntity.getApprovalprojecttype())) {
			 flowid = gpmWfFormService.queryFlowid(GpmSystemConst.SdApprovalType.GpmProcessProjectType, GpmSystemConst.SdApprovalCode.GpmProcessProjectApproval,this.getSessionUserBean());
		} else { // 通用管理项目立项
			 flowid = gpmWfFormService.queryFlowid(GpmSystemConst.SdApprovalType.SdProjectType, GpmSystemConst.SdApprovalCode.ProjectApproval,this.getSessionUserBean());
		}
		if (flowid <= 0) {
			throw new MessageException("未找到对应的合同谈判与签订签订审批流程，请联系管理员");
		}
		gpmWfFormEntity.setFlowid(flowid);
		gpmWfFormService.insert(gpmWfFormEntity);
		StringBufferProxy mailtitle = new StringBufferProxy();
		String flowname = "";
		// 流程管理项目立项
		if (GpmSystemConst.GPM_APPROVAL_PROJECT_TYPE.GpmProcessProject.equals(projectEntity.getApprovalprojecttype())) {
			flowname = "流程项目立项";
		} else { // 通用管理项目立项
			flowname = "项目立项";
		}
		mailtitle.appendSingle("{0}{1}于{2}提交{3}审批流程,单据编号{4}! ", this.getSessionUserBean().getDept().getFullname(),
				gpmWfFormEntity.getUsername(), com.topscomm.pub.util.DateUtil.dateToString(new Date(), "yyyy-MM-dd"),
				flowname, gpmWfFormEntity.getDocno());
		// 审批提交
		gpmWfFormService.executeSubmit(gpmWfFormEntity, mailtitle.toString(), this.getSessionUserBean());
		// 生成编号
		this.afterProjectApproval(projectEntity, gpmWfFormEntity.getSubmitdate());
	}

	/***
	 * @description: 立项提交审批后操作
	 * @param projectEntity
	 * @param submitDate
	 * @return
	 * @author: jiangtao1
	 * @date: 2021/11/30 10:22
	 * @modify:
	 */
	private void afterProjectApproval(GpmProjectEntity projectEntity, Date submitDate) {
		projectEntity.setState(1);
		String projectNumber = projectEntity.getProjectcode();
		projectEntity.setProjectnumber(projectNumber);
		this.updateEntity(projectEntity);
	}

	/***
	 * @description: 新增或更新主表信息
	 * @param gpmProjectEntity
	 * @return
	 * @author: jiangtao1
	 * @date: 2021/11/24 15:58
	 * @modify:
	 */
	private GpmProjectEntity saveProjectInfo(GpmProjectEntity gpmProjectEntity) {
		long id = gpmProjectEntity.getId();
		if (id <= 0) {
			long[] arrayId = PrimaryKeyUtil.GeneIDs(gpmProjectEntity.getTableName(), 1);
			id = arrayId[0];
			gpmProjectEntity.setId(id);
			gpmProjectEntity.setState(0);
			gpmProjectEntity.setProjectstate(GpmSystemConst.SdProjectState.ProjectApproval);
			String docNo = String.valueOf(id);
			docNo = "GPM" + docNo.substring(0, 6) + docNo.substring(9);
			gpmProjectEntity.setProjectcode(docNo);
			this.insert(gpmProjectEntity);
		} else {
			this.updateEntity(gpmProjectEntity);
		}
		return gpmProjectEntity;
	}

	/**
	 * @author: houyuhang
	 * @date: 2021-12-18
	 * @description: 获取首页是否有“公司数据”的权限
	 * @return: AtomicBoolean
	 */
	public AtomicBoolean getIndexPermission(Map<String,Object> paraMap) {
		AtomicBoolean hasOrg = new AtomicBoolean(false);
		// 根据系统参数判断当前登录用户是否有“公司数据”TAB页的权限
		String indexOrgTabPermissionRoles = "," + ParameterCache.getValue("GpmIndexOrgTabPermissionRoles") + ",";// 根据角色判断（数据的值为角色编码，多个角色以逗号隔开）
		// 如果当前用户的角色列表中包含任意一个系统参数中配置角色，则有orgTab页的权限
		List<CboRoleEntity> roleList = this.getUserBean().getRoleList();
		for(CboRoleEntity role : roleList) {
			// 排除角色code为空的情况
			if(StringUtil.isEmpty(role.getCode())) {
				continue;
			}
			if(indexOrgTabPermissionRoles.contains("," + role.getCode() + ",")) {
				hasOrg.set(true);
				break;
			}
		}
		return hasOrg;
	}
	/**
	 * @author: houyuhang
	 * @date: 2021-12-18
	 * @description: 获取当前登录用户
	 * @return: com.topscomm.tap.common.SessionUserBean
	 * @modify:
	 */
	public SessionUserBean getUserBean() {
		return ThreadLocalContext.sessionUserBeanThreadLocal.get();
	}
	/**
	 * @author: houyuhang
	 * @date: 2021-12-18
	 * @description: 获取最新创建和近期完成的项目
	 * @return: List<Map<String,Object>>
	 * @modify:
	 */
	public List<Map<String,Object>> queryRecentlyCreateOrComplete(Map<String,Object> paraMap) {
		DateTime beginDate = DateUtil.offsetMonth(new Date(), -1); // 一个月前的日期
		List<Map<String, Object>> result = null;
		String columnName = "";// 立项日期/结项日期的字段名称
		// 根据tab名称判断是查询最近创建还是近期完成
		if (ConvertUtil.convertToString(paraMap.get("tabName")).equals("recentlyCreat")) {
			columnName = "FINISHDATE";
		} else if (ConvertUtil.convertToString(paraMap.get("tabName")).equals("recentlyComplete")) {
			columnName = "ACTUALENDDATE";
		}
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" GpmProject.{2} BETWEEN {0} AND {1} ", SQLAdapter.toDateLong(DateUtil.formatDateTime(beginDate)),
				SQLAdapter.toDateLong(DateUtil.formatDateTime(new Date())), columnName);
		sql.appendSingle(" and {0} ", this.whereExistsSqlForIndex(GpmProjectEntity.tableName,
				GpmProjectEntity.FieldId, ConvertUtil.convertToString(paraMap.get("dataPermissionFlag"))));
		result = this.queryMapForPage(sql.toString(), 1, ConvertUtil.convertToInt(paraMap.get("pageSize")),
				ConvertUtil.convertToString(paraMap.get("sidx")), ConvertUtil.convertToString(paraMap.get("sord")));
		return result;
	}
	/**
	 * @description: 专用于生成首页查询关联SDPROJECT表的exist语句
	 * @param: tableNam 要查询的表名称
	 * @param: column 要查询的表名称和SDPROJECT表的projectcode关联字段名称
	 * @param: permissionFlage 权限标识（org：公司数据，inChargeMe：我负责的，participate：我参与的）
	 * @return: java.lang.String
	 * @author Administrator
	 * @date: 2021/1/7 18:33
	 */
	public String whereExistsSqlForIndex(String tableNam, String column, String permissionFlage) {
		StringBufferProxy sql = new StringBufferProxy();

		// 公司数据
		if ("org".equals(permissionFlage)) {
			// 如果是公司数据，则查询
			sql.appendSingle(this.spellSqlForDataBoard(new HashMap<>(),tableNam, column));
		} else if ("inChargeMe".equals(permissionFlage)) {
			// 我负责的（项目经理是我）
			sql.appendSingle(" EXISTS (SELECT id FROM GPMPROJECT existProject WHERE existProject.ID =  {0}.{1} and existProject.PROJECTMANAGERCODE='{2}'  )", tableNam, column, this.getUserBean().getUser().getCode());
		} else if ("participate".equals(permissionFlage)) {
			// 我参与的（项目组成员中有我）
			sql.appendSingle(" EXISTS (SELECT id FROM GPMPROJECT existProject WHERE existProject.ID = {0}.{1} and EXISTS (SELECT ID FROM GPMPROJECTTEAM GpmProjectTeam WHERE existProject.ID = GPMPROJECTTEAM.PROJECTID AND GPMPROJECTTEAM.USERCODE = '{2}' AND GPMPROJECTTEAM.STATE = 9  AND GPMPROJECTTEAM.ENABLED = 1)  )", tableNam, column, this.getUserBean().getUser().getCode());
		}
		return sql.toString();
	}
	/**
	 * @description: 首页数据看板、手机端首页的where条件拼接通用方法
	 * @param: paraMap
	 * @return: java.util.List<com.topscomm.sd.pojo.SdProjectEntity>
	 * @author Administrator
	 * @date: 2021/1/7 18:28
	 */
	public String spellSqlForDataBoard(Map<String, Object> paraMap, String tableName, String columnName) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" exists ( select existProject.PROJECTCODE from GPMPROJECT existProject  where 1=1 and {0}.{1} = existProject.id ", tableName, columnName);
		if (paraMap.containsKey("deptname")) {
			String value = ConvertUtil.convertToString(paraMap.get("deptname"));
			sql.appendSingle("AND EXISTS ( SELECT cbodept.code FROM cbodept WHERE existProject.deptcode = cbodept.CODE and cbodept.FULLNAME LIKE '%{0}%' ) ", value);
		}
		if (paraMap.containsKey("deptCodeArr")) {
			String value = ConvertUtil.convertToString(paraMap.get("deptCodeArr"));
			sql.appendSingle("AND existProject.deptcommoncode1 in ({0})", value);
		}
		if (paraMap.containsKey("projectname")) {
			String value = ConvertUtil.convertToString(paraMap.get("projectname"));
			sql.appendSingle("AND existProject.projectname like '%{0}%'  ", value);
		}
		if (paraMap.containsKey("projectstate")) {
			String value = ConvertUtil.convertToString(paraMap.get("projectstate"));
			if (!StringUtil.isEmpty(value)) {
				if (!value.contains(GpmSystemConst.SdProjectState.ProjectOngoing)) {
					sql.appendSingle(" and existProject.projectstate in ({0})", value);
				} else {
					sql.appendSingle(" and existProject.projectstate in ({0},{1})", GpmSystemConst.ProjectOngoingState, value);
				}
			}
		}
		if (paraMap.containsKey("query_projectlevel")) {
			String value = ConvertUtil.convertToString(paraMap.get("query_projectlevel"));
			sql.appendSingle("AND existProject.PROJECTLEVEL in ({0})  ", value);
		}
		if (paraMap.containsKey("abnormalstate")) {
			String value = ConvertUtil.convertToString(paraMap.get("abnormalstate"));
			sql.appendSingle("AND existProject.abnormalstate ='{0}'  ", value);
		}

		if (paraMap.containsKey("projectmanager")) {
			String value = ConvertUtil.convertToString(paraMap.get("projectmanager"));
			sql.appendSingle("AND (existProject.projectmanager  like '%{0}%' or existProject.projectmanagercode  like '%{0}%' ) ", value);
		}
		if (paraMap.containsKey("sponsor")) {
			String value = ConvertUtil.convertToString(paraMap.get("sponsor"));
			sql.appendSingle("AND (existProject.sponsor  like '%{0}%' or existProject.sponsorcode  like '%{0}%' ) ", value);
		}
		if (paraMap.containsKey("owner")) {
			String value = ConvertUtil.convertToString(paraMap.get("owner"));
			sql.appendSingle("AND (existProject.owner  like '%{0}%' or existProject.owner  like '%{0}%' ) ", value);
		}
		if (paraMap.containsKey("startDateForFinisthDate")) {
			String value = ConvertUtil.convertToString(paraMap.get("startDateForFinisthDate"));
			sql.appendSingle(" and  existProject.finishDate > {0}", SQLAdapter.toDateShort(value));
		}
		if (paraMap.containsKey("endDaterFinisthDate")) {
			String value = ConvertUtil.convertToString(paraMap.get("endDaterFinisthDate"));
			sql.appendSingle("  and  existProject.finishDate < {0}", SQLAdapter.toDateShort(value));
		}
		if (paraMap.containsKey("startDateForActualEndDate")) {
			String value = ConvertUtil.convertToString(paraMap.get("startDateForActualEndDate"));
			sql.appendSingle("  and  existProject.actualenddate > {0}", SQLAdapter.toDateShort(value));
		}
		if (paraMap.containsKey("endDateForActualEndDate")) {
			String value = ConvertUtil.convertToString(paraMap.get("endDateForActualEndDate"));
			sql.appendSingle(" and  existProject.actualenddate < {0}", SQLAdapter.toDateShort(value));
		}
		String dataPession = this.getDataPermission(TapSystemConst.TapOperationTypeEnum.Select, "", this.getUserBean());
		String deptcode = this.getUserBean().getDept().getCode();
		// 管理员、经营管理部可以查看超期里程碑等数据项，不设置权限
		if (this.getUserBean().getUser().getAdminlevel() < 1 && !"D141".equals(deptcode.substring(0, 4)) && !"2273".equals(deptcode.substring(0, 4)) && !"2425".equals(deptcode.substring(0, 4))) {
			// 管理员不控制权限，否则默认查询（我负责的、我参与的、所在一级部门的所有项目）
			sql.appendSingle(" and ( existProject.PROJECTMANAGERCODE='{0}' ", this.getUserBean().getUser().getCode()); // 我负责的
			sql.appendSingle(" or EXISTS (SELECT PROJECTCODE FROM GPMPROJECTTEAM GPMPROJECTTEAM WHERE existProject.ID = GPMPROJECTTEAM.PROJECTID AND GPMPROJECTTEAM.USERCODE = '{0}' AND GPMPROJECTTEAM.STATE = 9  AND GPMPROJECTTEAM.ENABLED = 1) ", this.getUserBean().getUser().getCode()); // 我参与的
			// 获取运营部门
			MmsDeptExtraInfoEntity mmsDeptExtraInfoEntity = this.queryDeptCommonCode(this.getUserBean().getDept().getCode());
			if(mmsDeptExtraInfoEntity != null) {
				// 存在运营部门，可以查看该运营部门下所有项目
				String deptcommoncode = mmsDeptExtraInfoEntity.getDeptcommoncode();
				sql.appendSingle(" or existProject.deptcommoncode1 = '{0}' ",deptcommoncode);
			}
			// 使用数据权限
			if (StringUtil.isEmpty(dataPession)) {
				sql.appendSingle(" ) ");
			} else {
				sql.appendSingle(" or {0}) ", dataPession);
			}
		}
		sql.appendSingle(" ) ");
		return sql.toString();
	}
	/**
	 * @description: 首页echarts数据
	 * @param: paraMap
	 * @return: Map<String,Object>
	 * @author houyuhang
	 * @date: 2021/12/01
	 */
	public Map<String,Object> queryProjectLevelSatistics(Map<String,Object> paraMap) {
		Map<String, Object> result = new HashMap<>();
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle("GPMPROJECT.state =9 and projectstate in ({0}) ", GpmSystemConst.ProjectOngoingState);
		sql.appendSingle(" and {0} ", this.whereExistsSqlForIndex(GpmProjectEntity.tableName,
				GpmProjectEntity.FieldId, ConvertUtil.convertToString(paraMap.get("dataPermissionFlag"))));
		// 按照项目级别统计
		List<Map<String, Object>> listForLevel = this.queryMapByWhere(sql.toString(), "projectLevelStatiStic");
		// 转换为Echarts需要的数据格式
		listForLevel = this.formatSdEchartsData("GpmProjectLevel",
				"projectlevel", "levelcount", listForLevel);
		// 按照项目状态统计
		List<Map<String, Object>> listForState = this.queryMapByWhere(sql.toString(), "projectStatStatiStic");
		// 转换为Echarts需要的数据格式
		listForState = this.formatSdEchartsData("GpmProjectAbnormalState",
				"abnormalstate", "statecount", listForState);
		result.put("projectLevelStatisticInfo", listForLevel);
		result.put("projectStateStatisticInfo", listForState);
		return result;
	}
	/**
	 * @description: 首页echarts数据格式转化
	 * @return: List<Map<String, Object>>
	 * @author houyuhang
	 * @date: 2021/12/01
	 */
	private List<Map<String, Object>> formatSdEchartsData(String dataName,String dataCode,String dataValue,List<Map<String, Object>> list) {
		DatacodeCache datacodeCache = (DatacodeCache) SpringUtil.getBean("datacodeCache");
		for (Map<String, Object> item : list) {
			// 转化为Echarts
			item.put("name", datacodeCache.getValueDynamic(dataName, ConvertUtil.convertToString(item.get(dataCode)), "code", "name"));
			item.put("code", ConvertUtil.convertToString(item.get(dataCode)));
			item.put("value", ConvertUtil.convertToInt(item.get(dataValue)));
			// 删除无用的key
			item.remove(dataCode);
			item.remove(dataValue);
		}
		return list;
	}
	/**
	 * @author: houyuhang
	 * @date: 2021-12-18
	 * @description: 获取即将超期的任务
	 * @return: List<Map<String,Object>>
	 * @modify:
	 */
	public List<Map<String,Object>> querySoonOverdueTask(Map<String,Object> paraMap) {
		DateTime dateTime = DateUtil.offsetDay(new Date(), ConvertUtil.convertToInt(paraMap.get("overdueDays")));// 获取N天后的时间
		StringBufferProxy sql = new StringBufferProxy();
		// 获取计划结束时间在今天和3天/一周之间，且已下发但是未开始或进行中的任务
		sql.appendSingle(" GpmProjectTask.PLANENDDATE BETWEEN {0} and {1} and GpmProjectTask.TASKSTATE in ('{2}','{3}') AND GpmProjectTask.STATE=9 ",
				SQLAdapter.toDateShort(DateUtil.format(new Date(), "yyyy-MM-dd")),
				SQLAdapter.toDateShort(DateUtil.format(dateTime, "yyyy-MM-dd")),
				GpmSystemConst.TaskStateCode.TaskNotStartCode, GpmSystemConst.TaskStateCode.TaskIncompleteCode);
		sql.appendSingle(" and {0} ", this.whereExistsSqlForIndex(GpmProjectTaskEntity.tableName, GpmProjectTaskEntity.FieldProjectid,
				ConvertUtil.convertToString(paraMap.get("dataPermissionFlag"))));
		List<Map<String, Object>> list = gpmProjectTaskService.queryMapForPage(sql.toString(), 1,
				ConvertUtil.convertToInt(paraMap.get("pageSize")), ConvertUtil.convertToString(paraMap.get("sidx")),
				ConvertUtil.convertToString(paraMap.get("sord")), "queryMapForPageForIndex");
		this.setDispFields(list);
		return list;
	}
	/**
	 * @author houyuhang
	 * @Description 首页信息概览内容
	 * @Date 2021/11/29
	 * @return List<Map<String,Object>>
	 **/
	public List<Map<String,Object>> queryOverdueInfo(Map<String, Object> paraMap) {
		List<Map<String, Object>> resultMapList = new ArrayList<>();
		// 查询任命待办数量
		resultMapList.add(gpmProjectAppointmentService.queryBacklogAppointment(paraMap));
		// 查询策划待办数量
		resultMapList.add(gpmProjectPlanService.queryBacklogPlan(paraMap));
		// 查询超期项目数量
		resultMapList.add(queryOverdueProject(paraMap));
		// 查询超期里程碑数量
		resultMapList.add(gpmProjectMilepostService.queryOverdueMilepost(paraMap));
		// 查询超期任务数量
		resultMapList.add(gpmProjectTaskService.queryOverdueTask(paraMap));
		// 查询任命超期数量
		resultMapList.add(gpmProjectAppointmentService.queryOverdueAppointment(paraMap));
		// 查询策划超期数量
		resultMapList.add(gpmProjectPlanService.queryOverduePlan(paraMap));
		return resultMapList;
	}
	/**
	 * @author houyuhang
	 * @Description 查询超期项目数量
	 * @Date 2021/11/29
	 * @return Map<String,Object>
	 **/
	public Map<String,Object> queryOverdueProject(Map<String, Object> paraMap) {
		Map<String, Object> overdueProjectResult = new HashMap<>();
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" GPMPROJECT.ABNORMALSTATE = '{0}' and GPMPROJECT.PROJECTSTATE in ({1}) and GPMPROJECT.ENABLED = 1 ",
				GpmSystemConst.AbnormalStateCode.OverdueProjectCode, GpmSystemConst.ProjectOngoingState);
		sql.appendSingle(" and {0} ", this.whereExistsSqlForIndex(GpmProjectEntity.tableName,
				GpmProjectEntity.FieldId, ConvertUtil.convertToString(paraMap.get("dataPermissionFlag"))));
		int countProject = this.getCount(sql.toString());
		overdueProjectResult.put("code", "overdueProjectNum");
		overdueProjectResult.put("name", "超期项目");
		overdueProjectResult.put("iconImg", "/static/images/paojectManager/overdueProject.png");
		overdueProjectResult.put("value", countProject);
		return overdueProjectResult;
	}
	/**
	 * @description: 获取数据看板中各个位置的组件信息
	 * @param: paraMap
	 * @return: List<Map<String,Object>>
	 * @author houyuhang
	 * @date: 2021/12/20
	 */
	public List<Map<String,Object>> getComponentsList(Map<String,Object> paraMap) {
		StringBufferProxy sql = new StringBufferProxy();
		// 处理角色级(用户可能有多个角色)
		StringBufferProxy sqlForRole = new StringBufferProxy();
		List<CboRoleEntity> roleList = this.getUserBean().getRoleList();
		// 如果用户有角色，将角色list使用逗号拼接成一个字符串
		if (roleList.size() > 0) {
			String roleStr = roleList.stream().map(role -> "'" + role.getCode() + "'").collect(Collectors.joining(","));
			sqlForRole.appendSingle(" or GpmDataBoardCustomizeRecord.rolecode in ({0}) ", roleStr);
		}
		sql.appendSingle(" and (GpmDataBoardCustomizeRecord.usercode = '{0}' {1}  or GpmDataBoardCustomizeRecord.ORGCODE = '{2}')  "
				, this.getUserBean().getUser().getCode(), sqlForRole.toString(), this.getUserBean().getOrg().getCode());
		List<Map<String, Object>> list = gpmDataBoardCustomizeRecordService.queryMapByWhere(sql.toString(), "queryRecordsForIndex");
		return list;
	}
	/**
	 * @description: 获取数据中心组件数据(整个系统中的数据统计)
	 * @param: paraMap
	 * @return: Map<String, Object>
	 * @author houyuhang
	 * @date: 2021/12/20
	 */
	public Map<String, Object> getDataCenterInfo(Map<String,Object> paraMap) {
		Map<String, Object> result = new HashMap<>();
		StringBufferProxy sql = new StringBufferProxy();
		// 查询项目个数(只统计立项通过的项目)
		sql.appendSingle("GPMPROJECT.state =9 and {0}", this.spellSqlForDataBoard(paraMap, GpmProjectEntity.tableName, GpmProjectEntity.FieldId));
		int count = this.getCount(sql.toString());
		result.put("count", count);
		// 查询项目金额（立项通过的所有立项单据）
		sql.clear();
		sql.appendSingle("GPMPROJECT.state =9 and {0}", spellSqlForDataBoard(paraMap, GpmProjectEntity.tableName, GpmProjectEntity.FieldId));
		List<Map<String, Object>> list = this.queryMapByWhere(sql.toString(), "projectMoneyStatiStic");
		result.put("money", list.size() > 0 ? ConvertUtil.convertToDouble(list.get(0).get("sumparticipatemoney")) : 0);
		return result;
	}
	/**
	 * @description: 获取项目数量Top10
	 * @param: paraMap
	 * @return: com.topscomm.pub.vo.ResponseResult<java.lang.Object>
	 * @author Administrator
	 * @date: 2021/1/13 10:24
	 */
	public List<Map<String, Object>> getProjectCountTop10(Map<String,Object> paraMap) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" state = 9 and {0}", spellSqlForDataBoard(paraMap, GpmProjectEntity.tableName, GpmProjectEntity.FieldId));
		List<Map<String, Object>> list = this.queryMapByWhere(sql.toString(), "projectCountTop10");
		this.setDispFields(list);
		return list;
	}
	/**
	 * @description: 获取金额Top10
	 * @param: paraMap
	 * @return: com.topscomm.pub.vo.ResponseResult<java.lang.Object>
	 * @author Administrator
	 * @date: 2021/1/13 8:38
	 */
	public List<Map<String, Object>> getMoneyTop10(Map<String,Object> paraMap) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" state = 9 and {0}", spellSqlForDataBoard(paraMap, GpmProjectEntity.tableName, GpmProjectEntity.FieldId));
		List<Map<String, Object>> list = this.queryMapByWhere(sql.toString(), "projectMoneyTop10");
		this.setDispFields(list);
		return list;
	}
	/**
	 * @description: 数据看板上项目级别饼图信息
	 * @param: paraMap
	 * @return: List<Map<String, Object>>
	 * @author houyuhang
	 * @date: 2021/12/01
	 */
	public List<Map<String, Object>> getDataBoardProjectLevelEhartInfo(Map<String,Object> paraMap) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" GPMPROJECT.state=9 ");
		sql.appendSingle(" and {0} ", this.spellSqlForDataBoard(paraMap, GpmProjectEntity.tableName, GpmProjectEntity.FieldId));
		// 按照项目级别统计
		List<Map<String, Object>> listForLevel = this.queryMapByWhere(sql.toString(), "projectLevelStatiStic");
		// 转换为Echarts需要的数据格式
		listForLevel = this.formatSdEchartsData("GpmProjectLevel",
				"projectlevel", "levelcount", listForLevel);
		return listForLevel;
	}
	/**
	 * @description: 查询各个省区的项目级别数量情况
	 * @param: paraMap
	 * @return: Map<String, Object>
	 * @author houyuhang
	 * @date: 2021/12/20
	 */
	public Map<String, Object> queryProvincesProjectLevelsInfo(Map<String,Object> paraMap) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" state = 9 and {0}", spellSqlForDataBoard(paraMap, GpmProjectEntity.tableName, GpmProjectEntity.FieldId));
		List<Map<String, Object>> list = this.queryMapByWhere(sql.toString(), "getProjectLevelsCount");
		// 处理为echarts数据格式
		Map<String,Object> result = this.formatEchartsDataForProjectLevel(new ArrayList<>(), new ArrayList<>(),
				new ArrayList<>(), new ArrayList<>(), new ArrayList<>(),list);
		return result;
	}
	/**
	 * @description: 处理各个省区的项目级别数量情况为Echarts数据
	 * @return: Map<String, Object>
	 * @author houyuhang
	 * @date: 2021/12/20
	 */
	private Map<String,Object> formatEchartsDataForProjectLevel(List<String> categoryList,List<String> ACountList,List<String> BCountList,
																List<String> CCountList,List<String> DCountList,List<Map<String,Object>> list) {
		DatacodeCache datacodeCache = (DatacodeCache) SpringUtil.getBean("datacodeCache");
		Map<String, Object> result = new HashMap<>();
		for (Map<String, Object> item : list) {
			// 获取省区的名称
			String deptCommonCode = ConvertUtil.convertToString(item.get("deptcommoncode1"));
			String deptName = datacodeCache.getValueDynamic("DeptCommonCode", deptCommonCode, "code", "name");
			categoryList.add(deptName);
			ACountList.add(ConvertUtil.convertToString(item.get("A")));
			BCountList.add(ConvertUtil.convertToString(item.get("B")));
			CCountList.add(ConvertUtil.convertToString(item.get("C")));
			DCountList.add(ConvertUtil.convertToString(item.get("D")));
		}
		result.put("categoryList", categoryList);
		result.put("ACountList", ACountList);
		result.put("BCountList", BCountList);
		result.put("CCountList", CCountList);
		result.put("DCountList", DCountList);
		return result;
	}
	public Page listForSdIndexController(Map<String,Object> paraMap) {
		Query query = new Query(paraMap);
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" GPMPROJECT.state = 9 and {0}", spellSqlForDataBoard(paraMap,
				GpmProjectEntity.tableName, GpmProjectEntity.FieldId));
		String sqlWhere = sql.toString();
		int totalCount = this.getCount(sqlWhere);
		List<Map<String, Object>> tempList = null;
		if (query.getPageSize() > 0) {
			tempList = this.queryMapForPage(sqlWhere, query.getCurrentPage(), query.getPageSize(),
					query.getSidx(), query.getSord(), "queryMapForPageForIndex");
		} else {
			tempList = this.queryMapByWhere(sqlWhere);
		}
        for (Map<String, Object> mapRow : tempList) {
            setCurrentMilePost(mapRow);
        }
		this.setDispFields(tempList);
		Page page = new Page(tempList, totalCount, query.getPageSize(), query.getCurrentPage());
		return page;
	}
	/**
	 * @Title: 获取任命超期/任命待办数据
	 * @description:
	 * @param paraMap
	 * @return
	 * @author: houyuhang
	 * @date: 2021年12月21日
	 */
	public Page queryAppointmentOverDate(Map<String, Object> paraMap,String whereSql) {
		paraMap = BaseUtil.decodeSecureMap(paraMap);
		Query query = new Query(paraMap);
		Map<String, Object> tempMap = new HashMap<>();
		if(ConvertUtil.convertToInt(paraMap.get("qry_overdue")) == 1) {
			// 获取4天之前的日期
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(new Date());
			String overdueAppointmentTime = GpmSystemConst.overdueAppointmentTime;
			int time = Integer.parseInt(overdueAppointmentTime) * (-1);
			calendar.add(Calendar.DATE,time);
			Date overdueDate = calendar.getTime();
			String overdueTime = com.topscomm.pub.util.DateUtil.dateToString(overdueDate,"yyyy-MM-dd");
			tempMap.put("overdue",1);
			tempMap.put("overduetime",overdueTime);
		}
		int currentPage = query.getCurrentPage();
		int pageSize = query.getPageSize();
		int begincount = currentPage * pageSize - pageSize;
		tempMap.put("sidx", query.getSidx());
		tempMap.put("sord", query.getSord());
		tempMap.put("pagesize", pageSize);
		tempMap.put("begincount", begincount);
		tempMap.put("whereSql", whereSql);
		// 查询项目总数
		int totalCount = this.getCount(tempMap,"queryAppointmentOverdue");
		List<Map<String, Object>> tempList = null;
		if (query.getPageSize() > 0) {
			tempList = this.queryMapForPage(tempMap, "queryAppointmentOverduePage");
		} else {
			tempList = this.queryMapByWhere(whereSql, "queryAppointmentOverdue");
		}
		this.setDispFields(tempList);
		// 单据状态
		for(Map<String, Object> temp : tempList) {
			if(ConvertUtil.convertToString(temp.get("dispstate")).isEmpty()) {
				temp.put("dispstate","未创建");
			}
		}
		// 超期天数
		String overdueTime = GpmSystemConst.overdueAppointmentTime;
		overdueDatetime(tempList, overdueTime);
		Page page = new Page(tempList, totalCount, query.getPageSize(), query.getCurrentPage());
		return page;
	}
	/**
	 * @Title: 获取策划超期/策划待办数据
	 * @description:
	 * @param paraMap
	 * @return
	 * @author: houyuhang
	 * @date: 2021年12月21日
	 */
	public Page queryPlanOverDate(Map<String, Object> paraMap,String whereSql) {
		paraMap = BaseUtil.decodeSecureMap(paraMap);
		Query query = new Query(paraMap);
		Map<String, Object> tempMap = new HashMap<>();
		if(ConvertUtil.convertToInt(paraMap.get("qry_overdue")) == 1) {
			// 获取7天之前的日期
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(new Date());
			String overduePlanTime = GpmSystemConst.overduePlanTime;
			int time = Integer.parseInt(overduePlanTime) * (-1);
			calendar.add(Calendar.DATE,time);
			Date overdueDate = calendar.getTime();
			String overdueTime = com.topscomm.pub.util.DateUtil.dateToString(overdueDate,"yyyy-MM-dd");
			tempMap.put("overdue",1);
			tempMap.put("overduetime",overdueTime);
		}
		int currentPage = query.getCurrentPage();
		int pageSize = query.getPageSize();
		int begincount = currentPage * pageSize - pageSize;
		tempMap.put("sidx", query.getSidx());
		tempMap.put("sord", query.getSord());
		tempMap.put("pagesize", pageSize);
		tempMap.put("begincount", begincount);
		tempMap.put("whereSql", whereSql);
		// 查询项目总数
		int totalCount = this.getCount(tempMap,"queryPlanOverdue");
		List<Map<String, Object>> tempList = null;
		if (query.getPageSize() > 0) {
			tempList = this.queryMapForPage(tempMap, "queryPlanOverduePage");
		} else
			tempList = this.queryMapByWhere(whereSql, "queryPlanOverdue");
		this.setDispFields(tempList);
		// 单据状态
		for(Map<String, Object> temp : tempList) {
			if(ConvertUtil.convertToString(temp.get("dispstate")).isEmpty()) {
				temp.put("dispstate","未创建");
			}
		}
		// 超期天数
		String overdueTime = GpmSystemConst.overduePlanTime;
		overdueDatetime(tempList, overdueTime);
		Page page = new Page(tempList, totalCount, query.getPageSize(), query.getCurrentPage());
		return page;
	}
	/**
	 * @Title: list
	 * @description:
	 * @param paraMap
	 * @return
	 * @author: lanjianwei
	 * @date: 2020年12月29日下午3:50:45
	 * @modify:
	 */
	public Page queryProjectOverdue(Map<String, Object> paraMap,String whereSql) {
		paraMap = BaseUtil.decodeSecureMap(paraMap);
		Query query = new Query(paraMap);
		Map<String, Object> tempMap = new HashMap<>();
		int currentPage = query.getCurrentPage();
		int pageSize = query.getPageSize();
		int begincount = currentPage * pageSize - pageSize;
		tempMap.put("sidx", query.getSidx());
		tempMap.put("sord", query.getSord());
		tempMap.put("pagesize", pageSize);
		tempMap.put("begincount", begincount);
		tempMap.put("whereSql", whereSql);
		// 查询项目总数
		int totalCount = this.getCount(whereSql);
		List<Map<String, Object>> tempList = null;
		if (query.getPageSize() > 0) {
			tempList = this.queryMapForPage(tempMap, "overdateProjectList");
		} else {
			tempList = this.queryMapByWhere(whereSql);
		}
		// 如果请求的内容为空，直接return
		if (tempList.size() == 0) {
			return new Page(tempList, totalCount, query.getPageSize(), query.getCurrentPage());
		}
		// 超期项目返回当前里程碑
		if (paraMap.get("qry_currentmilepost") != null) {
			for (Map<String, Object> mapRow : tempList) {
				this.setCurrentMilePost(mapRow);
			}
		}
		// 导出数据时获取督办情况,机会点编号调用此函数
		String projectIds = getProjectIds(tempList);
		if (paraMap.containsKey("notQueryForPageFlag")) {
			setSuperviseListForExcel(tempList, projectIds);
			setChanceClueForExcel(tempList);
		} else {
			// 项目监管查询所有可查看项目各自的督办情况
			setSuperviseListForList(tempList, projectIds);
		}
		this.setDispFields(tempList);
		return new Page(tempList, totalCount, query.getPageSize(), query.getCurrentPage());
	}
	/**
	 * @Title: 获取当前里程碑
	 * @description:
	 * @param mapRow
	 * @return
	 * @author: houyuhang
	 * @date: 2021年12月21日
	 * @modify:
	 */
	public void setCurrentMilePost(Map<String, Object> mapRow) {
		String temp = mapRow.get("id").toString();
		StringBufferProxy sql = new StringBufferProxy();
		// 获取处于未达成状态的、创建时间最早的里程碑
		sql.appendSingle("projectid = '{0}' and milepoststate = 0 and enabled = 1", temp);
		List<GpmProjectMilepostEntity> milepostEntities = gpmProjectMilepostService.queryByWhere(sql.toString());
		if (!milepostEntities.isEmpty()) {
			String milepost = "";
			Date currentDate = milepostEntities.get(0).getCreateon();
			// 根据里程碑创建时间判断
			for (GpmProjectMilepostEntity milepostEntity : milepostEntities) {
				if (milepostEntity.getCreateon().compareTo(currentDate) <= 0) {
					currentDate = milepostEntity.getCreateon();
					milepost = milepostEntity.getMilepostname();
				}
			}
			mapRow.put("currentmilepost", milepost);
		} else {
			mapRow.put("currentmilepost", "暂无未达成的里程碑");
		}
	}
	/**
	 * @Title: 项目监管页面获取各项目督办情况(项目监管页面加载用）
	 * @description:
	 * @param tempList
	 * @return
	 * @author: houyuhang
	 * @date: 2021年12月22日
	 * @modify:
	 */
	private void setSuperviseListForList(List<Map<String, Object>> tempList, String projectIds) {
		StringBufferProxy sql = new StringBufferProxy();
		// 查询督办表获取所有项目的督办情况
		sql.appendSingle("projectid in ({0})", projectIds);
		List<Map<String, Object>> superviseMap = gpmProjectSuperviseService.queryMapByWhere(sql.toString());
		if (!superviseMap.isEmpty()) {
			// 转为以projectcode区分的督办list
			Map<String, List<Map<String, Object>>> dataMap = superviseMap.stream()
					.collect(Collectors.groupingBy(map -> ConvertUtil.convertToString(map.get("projectId"))));
			for (Map<String, Object> mapRow : tempList) {
				mapRow.put("superviselist", dataMap.get(ConvertUtil.convertToString(mapRow.get("id"))));
			}
		}
	}
	/**
	 * @Title: 返回所有项目的id作为查询条件
	 * @description:
	 * @param tempList
	 * @return
	 * @author: houyuhang
	 * @date: 2021年12月22日
	 * @modify:
	 */
	private String getProjectIds(List<Map<String, Object>> tempList) {
		List<String> codeList = new ArrayList<String>();
		for (Map<String, Object> mapRow : tempList) {
			String projectCode = "'" + ConvertUtil.convertToString(mapRow.get("id")) + "'";
			codeList.add(projectCode);
		}
		return String.join(",", codeList);
	}
	/**
	 * @Title: 获取各项目督办情况（excel导出时使用）
	 * @description:
	 * @param tempList
	 * @return
	 * @author: houyuhang
	 * @date: 2021年12月24日
	 * @modify:
	 */
	private void setSuperviseListForExcel(List<Map<String, Object>> tempList, String projectIds) {
		StringBufferProxy sql = new StringBufferProxy();
		// 查询督办表获取所有项目的督办情况
		sql.appendSingle("projectid in ({0})", projectIds);
		List<Map<String, Object>> superviseMap = gpmProjectSuperviseService.queryMapByWhere(sql.toString());
		if (!superviseMap.isEmpty()) {
			// 转为以projectid区分的督办list
			Map<String, List<Map<String, Object>>> dataMap = superviseMap.stream()
					.collect(Collectors.groupingBy(map -> ConvertUtil.convertToString(map.get("projectid"))));
			for (Map<String, Object> mapRow : tempList) {
				List<Map<String, Object>> dataList = dataMap.get(ConvertUtil.convertToString(mapRow.get("id")));
				String superviseList = "";
				if (!CollectionUtils.isEmpty(dataList)) {
					List<String> superviseStr = new ArrayList<String>();
					for (Map<String, Object> supervise : dataList) {
						String str = ConvertUtil.convertToString(supervise.get(GpmProjectSuperviseEntity.FieldSupervisecode)) + " " +
								supervise.get("dispsupervisestate");
						superviseStr.add(str);
					}
					superviseList = String.join("\n", superviseStr);
				}
				mapRow.put("superviselist", superviseList);
			}
		}
	}

	/**
	 * @Title: 获取各项目机会点情况（excel导出时使用）
	 * @description:
	 * @param tempList
	 * @return
	 * @author: houyuhang
	 * @date: 2021年12月24日
	 * @modify:
	 */
	private void setChanceClueForExcel(List<Map<String, Object>> tempList) {
		for (Map<String, Object> mapRow : tempList) {
			String chanceClues = ConvertUtil.convertToString(mapRow.get("chanceclue"));
			if (chanceClues.contains(",")) {
				chanceClues = chanceClues.replace(",", "\n");
				mapRow.put("chanceclue", chanceClues);
			}
		}
	}
	/**
	 * 导出excel
	 *
	 * @description:
	 * @param fileName
	 * @param columns
	 * @return
	 * @author: donghang
	 * @date: 2020年5月26日上午10:52:17
	 * @modify:
	 */
	@SuppressWarnings("rawtypes")
	public void exportExcelXlsx(HttpServletResponse response, ResponseResult<Object> responseResult, String fileName,
								 String columns) throws Exception {
		if (ConvertUtil.convertToString(fileName).length() == 0) {
			fileName = "导出数据表.xlsx";
		}
		if (!ConvertUtil.convertToString(fileName).contains("xlsx")) {
			fileName = fileName + ".xlsx";
		}
		InputStream inputStream = null;
		try {
			//设定最大导出行
			Page result = (Page) responseResult.getResult();
			List<Map<String, Object>>  dataList =(List<Map<String, Object>>) result.getDataList();
			int totalCount =  dataList.size();
			int exportMaxCount = ParameterCache.getIntValue("CboExcelInDirectMaxCount", 1000000);
			if (totalCount > exportMaxCount) {
				throw new BusinessException("最大允许导出" + exportMaxCount + "行");
			}
			// 是否直接相应，数量少的直接相应
			int exportDirectMaxCount = ParameterCache.getIntValue("CboExcelDirectMaxCount", 20000);
			boolean isResponse = totalCount < exportDirectMaxCount;
			if (isResponse) {
				//重新填充返回数据，将含有多个机会点的数据扩充至多条，并合并单元格
//              parseChanceClueData(dataList);
				//合并单元格导出
				inputStream = exportExeclXlsx(dataList, columns.split(","));
			}
			// 文件流直接相应
			response.setContentType("application/vnd.ms-excel");
			response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
			response.setHeader("istaskexport", "0");
			// 需要添加否则前台得不到istaskexport
			response.setHeader("Access-Control-Expose-Headers", "istaskexport");
			response.setHeader("FileName", URLEncoder.encode(fileName, "utf-8"));
			response.setHeader("Access-Control-Expose-Headers", "FileName");
			OutputStream outStream = response.getOutputStream();
			byte[] bytes = new byte[2048];
			int len;
			while (inputStream!= null && (len = inputStream.read(bytes)) != -1) {
				outStream.write(bytes, 0, len);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(inputStream!=null) {
				inputStream.close();
			}
		}

	}
	/**
	 * 项目监管机会点合并单元格操作方法
	 * @param listMap
	 * @param columns
	 * @return
	 * @throws Exception
	 */
	private InputStream exportExeclXlsx(List<Map<String, Object>> listMap, String[] columns) throws Exception {
		int rowIndex = 0;
		XSSFWorkbook wb = new XSSFWorkbook();
		// 表头格式
		XSSFCellStyle headCellStyle = wb.createCellStyle();
		headCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 上下居中
		headCellStyle.setAlignment(HorizontalAlignment.CENTER); // 居中
		XSSFFont font = wb.createFont();
		font.setFontName(I18nUtil.getMessage("tap.common.songti"));
		font.setBold(true);
		headCellStyle.setFont(font);
		// 表行格式
		XSSFCellStyle lineCellStyle = wb.createCellStyle();
		lineCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 上下居中
		lineCellStyle.setAlignment(HorizontalAlignment.CENTER);
		lineCellStyle.setBorderLeft(BorderStyle.THIN);
		lineCellStyle.setBorderRight(BorderStyle.THIN);
		lineCellStyle.setBorderTop(BorderStyle.THIN);
		lineCellStyle.setBorderBottom(BorderStyle.THIN);
		lineCellStyle.setWrapText(true);
		// 表头
		XSSFSheet sheet = wb.createSheet("sheet1");
		XSSFRow row = sheet.createRow(rowIndex++);
		int changePointCol = 6;
		for (int i = 0; i < columns.length; i++) {
			//获取机会点列值
			if(columns[i].equals("chanceclue;机会点")){
				changePointCol = i;
			}
			XSSFCell cell = row.createCell(i);
			cell.setCellStyle(headCellStyle);
			String[] kv = columns[i].split(";");
			String value = kv[1];
			cell.setCellValue(value);
		}
		// 表行
		for (Map<String, Object> data : listMap) {
			//合并单元格
			if(!NULL.equals(String.valueOf(data.get("chanceclueNum"))) && !StringUtils.isBlank(String.valueOf(data.get("chanceclueNum")))){
				int redRow =Integer.parseInt(String.valueOf(data.get("chanceclueNum")));
				//确定合并行类数
				int rowInfo = rowIndex + redRow;
				for(int i = 0;i<columns.length;i++) {
					//机会点列不合并
					if(i != changePointCol){
						sheet.addMergedRegion(new CellRangeAddress(rowIndex , rowInfo-1, i, i));
					}
				}

			}
			row = sheet.createRow(rowIndex++);
			for (int i = 0; i < columns.length; i++) {
				String[] kv = columns[i].split(";");
				String key = kv[0];
				XSSFCell cell = row.createCell(i);
				String value = "";
				if (!StringUtil.isEmpty(key) && data.get(key) != null) {
					if (data.get(key) instanceof Date) {
						value = com.topscomm.pub.util.DateUtil.dateToString((Date) data.get(key));
						cell.setCellValue(value);
					} else if (data.get(key) instanceof BigDecimal || data.get(key) instanceof Double
							|| data.get(key) instanceof Float) {
						Double d = ConvertUtil.convertToDouble(data.get(key));
						cell.setCellValue(d);
					} else {
						value = data.get(key).toString();
						cell.setCellValue(value);
					}
				}
				cell.setCellStyle(lineCellStyle);
			}
		}
		// 自适应列
		int columnCount = columns.length;
		for (int i = 0; i < columnCount; i++) {
			sheet.autoSizeColumn(i);
			int colWidth = sheet.getColumnWidth(i) * 17 / 10;
			if (colWidth < 255 * 256) {
				sheet.setColumnWidth(i, colWidth);
			} else {
				sheet.setColumnWidth(i, 6000);
			}
		}
		// 生成流
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		InputStream is = null;
		try {
			wb.write(os);
			os.flush();
			byte[] content = os.toByteArray();
			is = new ByteArrayInputStream(content);
		} catch (Exception ex) {
			if (os != null) {
				os.close();
				os = null;
			}
			if (wb != null) {
				wb.close();
			}
		}
		return is;
	}
	/**
	 * 计算超期天数
	 * @param tempList
	 * @param overdueTime
	 * @return
	 */
	void overdueDatetime(List<Map<String, Object>> tempList,String overdueTime) {
		for(Map<String, Object> temp : tempList) {
			BigDecimal time = ConvertUtil.convertToBigDecimal(temp.get("daynum"));
			temp.put("daynum",time.subtract(ConvertUtil.convertToBigDecimal(overdueTime)));
		}
	}

	/***
	 * @description: 添加审批历史信息
	 * @param projectcode
	 * @return
	 * @author: jiangtao1
	 * @date: 2021/12/30 13:51
	 * @modify:
	 */
	public void generateHistoryInfo(String projectcode) {
		GpmProjectEntity gpmProjectEntity = this.queryObjectByWhere(" projectcode = '" + projectcode + "'");
		if(gpmProjectEntity == null) {
			return;
		}
		GpmProjectHistoryEntity gpmProjectHistoryEntity = new GpmProjectHistoryEntity();
		BeanUtils.copyProperties(gpmProjectEntity, gpmProjectHistoryEntity);
		gpmProjectHistoryEntity.setProjectid(gpmProjectEntity.getId());
		long[] arrayId = PrimaryKeyUtil.GeneIDs(gpmProjectHistoryEntity.getTableName(), 1);
		gpmProjectHistoryEntity.setId(arrayId[0]);
		gpmProjectHistoryService.insert(gpmProjectHistoryEntity);
	}
	/**
	 * @author: houyuhang
	 * @date: 2022-01-04
	 * @description: 执行项目异常状态检测
	 * @modify:
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void executeCheckJob() {
		StringBufferProxy sqlWhere = new StringBufferProxy();
		sqlWhere.appendSingle(" projectstate in ({0}) ", GpmSystemConst.ProjectOngoingState);
		// 查询所有正在进行的项目
		List<GpmProjectEntity> sdProjectEntities = this.queryByWhere(sqlWhere.toString());
		// 遍历检测更新
		sdProjectEntities.forEach(item -> {
			this.checkProjectAbnormalState(item.getProjectcode());
		});
		sqlWhere.clear();
		sqlWhere.appendSingle(" projectstate in (0,{0}) ", GpmSystemConst.ProjectOngoingState);
		List<GpmProjectEntity> entities = this.queryByWhere(sqlWhere.toString());
		// 最后统一判断项目相关的所有审批流是否在两天之内完成
		this.checkOverdueApprovalFlow(entities);

		//把已结项的项目的项目异常状态全部置为正常
		sqlWhere.clear();
		sqlWhere.appendSingle(" projectstate in (2,8) AND ABNORMALSTATE!=0 ");
		List<GpmProjectEntity> gpmProjectEntityList = this.queryByWhere(sqlWhere.toString());
		List<BasicEntity> entityList = new ArrayList<>();
		if(gpmProjectEntityList.size()>0){
			for(GpmProjectEntity entity: gpmProjectEntityList){
				entity.setAbnormalstate(0);
				entityList.add(entity);
			}
			this.updateBatch(entityList);
		}
	}
	/**
	 * @description: 检测、更新项目异常状态，项目异常历史以json字符串的格式保存到abnormalreason字段中
	 * [{addDate:2021-01-27,content:'项目超期'}]
	 * @param: projectId
	 * @return: com.topscomm.pub.vo.ResponseResult<java.lang.Object>
	 * @author Administrator
	 * @date: 2021/1/27 8:52
	 */
	public void checkProjectAbnormalState(String projectCode) {
		StringBufferProxy sqlWhere = new StringBufferProxy();
		sqlWhere.appendSingle(" projectcode = '{0}' ", projectCode);
		// 需要更新的项目
		Map<String, Object> updateMap = new HashMap<>();
		// 检测项目是否超期
		List<GpmProjectEntity> sdProjectEntities = this.queryByWhere(sqlWhere.toString());
		Date currentDate = null;
		try {
			SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
			currentDate = simpleDateFormat.parse(simpleDateFormat.format(new Date()));
		} catch (ParseException pe) {
			pe.printStackTrace();
			throw new MessageException("日期错误，请填写正确格式的日期！");
		}
		if (sdProjectEntities.size() > 0 && (currentDate.getTime() > sdProjectEntities.get(0)
				.getPlanenddate().getTime())) {
			updateMap.put("id", sdProjectEntities.get(0).getId());
			updateMap.put("abnormalstate", "30");
			this.update(updateMap);
			return;
		}
		// 检测是否任命、策划超期
		if (checkAppointAndPlanOverdue(projectCode, sdProjectEntities)) {
			return;
		}
		// 检测是否有超期里程碑、超期任务
		sqlWhere.clear();
		sqlWhere.appendSingle(" projectcode = '{0}' and planfinishtime<{1}  and milepoststate=0 and ENABLED=1 ",
				projectCode, SQLAdapter.toDateLong(DateUtil.format(new Date(), "yyyy-MM-dd 00:00:00")));
		int overTimeMilepostCount = gpmProjectMilepostService
				.getCount(sqlWhere.toString());// 超期里程碑数量
		if (overTimeMilepostCount > 0) {
			updateMap.put("id", sdProjectEntities.get(0).getId());
			updateMap.put("abnormalstate", "20");
			this.update(updateMap);
			return;
		}
		// 检测是否有超期任务
		sqlWhere.clear();
		sqlWhere.appendSingle(
				" projectcode = '{0}' and planenddate<{1} and state=9 and taskstate in (0,1)",
				projectCode, SQLAdapter.toDateLong(DateUtil.format(new Date(), "yyyy-MM-dd 00:00:00")));
		int overTimeTaskCount = gpmProjectTaskService.getCount(sqlWhere.toString());// 超期任务数量
		if (overTimeTaskCount > 0) {
			updateMap.put("id", sdProjectEntities.get(0).getId());
			updateMap.put("abnormalstate", "10");
			this.update(updateMap);
			return;
		}
		updateMap.put("id", sdProjectEntities.get(0).getId());
		updateMap.put("abnormalstate", "0");
		this.update(updateMap);
    }
	/**
	 * @author: houyuhang
	 * @date: 2022-09-07
	 * @description: 判断任命和策划超期
	 * @modify:
	 */
	public Boolean checkAppointAndPlanOverdue(String projectCode,List<GpmProjectEntity> sdProjectEntities) {
		// 判断项目是否任命超期
		StringBufferProxy sql = new StringBufferProxy();
		String finishstr = GpmProjectEntity.tableName + "." + GpmProjectEntity.FieldFinishdate + ", 'yyyy-MM-dd'";
		String sysstr = SQLAdapter.getDate() + "-" + GpmSystemConst.overdueAppointmentTime + ", 'yyyy-MM-dd'";
		sql.appendSingle(" {0}.enabled = 1 and {1} < {2} and {0}.projectcode = '{3}' ", GpmProjectEntity.tableName, SQLAdapter.toChar(finishstr), SQLAdapter.toChar(sysstr), projectCode);
		sql.appendSingle(" and ({0} = 0 or ({1}.state < 9 and {1}.version = 1)) ", SQLAdapter.isNull(GpmProjectAppointmentEntity.tableName + "." + GpmProjectAppointmentEntity.FieldId, "0"), GpmProjectAppointmentEntity.tableName);
		List<Map<String, Object>> appointOverdueList = this.queryMapByWhere(sql.toString(), "checkAppointOverdue");
		if (!CollectionUtil.isEmpty(appointOverdueList)) {
			Map<String, Object> updateMap = new HashMap<>();
			updateMap.put("id", sdProjectEntities.get(0).getId());
			updateMap.put("abnormalstate", "30");
			this.update(updateMap);
			return true;
		}
		// 判断项目是否策划超期
		sql.clear();
		String finishPlanStr = GpmProjectAppointmentEntity.tableName + "." + GpmProjectAppointmentEntity.FieldSigndate + ", 'yyyy-MM-dd'";
		String sysPlanStr = SQLAdapter.getDate() + "-" + GpmSystemConst.overduePlanTime + ", 'yyyy-MM-dd'";
		sql.appendSingle(" {0} < {1} and {2}.version = 1 and {2}.signdate is not null and {2}.projectcode = '{3}' ",
				SQLAdapter.toChar(finishPlanStr), SQLAdapter.toChar(sysPlanStr), GpmProjectAppointmentEntity.tableName, projectCode);
		sql.appendSingle(" and ({0} = 0 or ({1}.state < 9 and {1}.version = 1)) ", SQLAdapter.isNull(GpmProjectPlanEntity.tableName + "." + GpmProjectPlanEntity.FieldId, "0"), GpmProjectPlanEntity.tableName);
		List<Map<String, Object>> planOverdueList = this.queryMapByWhere(sql.toString(), "checkPlanOverdue");
		if (!CollectionUtil.isEmpty(planOverdueList)) {
			Map<String, Object> updateMap = new HashMap<>();
			updateMap.put("id", sdProjectEntities.get(0).getId());
			updateMap.put("abnormalstate", "30");
			this.update(updateMap);
			return true;
		}
		return false;
	}
	/**
	 * @author: houyuhang
	 * @date: 2022-01-04
	 * @description: 判断项目相关所有审批流是否有超期的
	 * @modify:
	 */
	private void checkOverdueApprovalFlow(List<GpmProjectEntity> sdProjectEntities) {
		// 获取之前距今两个工作日的日期
		StringBufferProxy whereSql = new StringBufferProxy();
		whereSql.appendSingle("sourcetype like 'GpmProject%' and state != '2' and state != '9' and startdate + 2 < {0}",
				SQLAdapter.toDateShort(DateUtil.formatDate(new Date())));
		List<CboApprovalFlowInsEntity> cboApprovalFlowInsEntities = this.cboApprovalFlowInsService
				.queryByWhere(whereSql.toString());
		if (!cboApprovalFlowInsEntities.isEmpty()) {
			// 修改项目状态
			this.updateAbnormalStateByFlowinds(sdProjectEntities, cboApprovalFlowInsEntities);
		}
	}
	/**
	 * @author: houyuhang
	 * @date: 2022-01-04
	 * @description: 将所有超期审批流所关联的项目状态置为流程超期
	 * @modify:
	 */
	private void updateAbnormalStateByFlowinds(List<GpmProjectEntity> sdProjectEntities,
											   List<CboApprovalFlowInsEntity> cboApprovalFlowInsEntities) {
		// 将项目实体按照projectcode分组，便于之后查找
		Map<String, List<GpmProjectEntity>> sdProjectListMap = sdProjectEntities.stream()
				.filter(map->map.getProjectcode()!=null)
				.collect(Collectors.groupingBy(item -> item.getProjectcode()));
		// 将审批流实例按照sourcetype分组，减少查询次数
		Map<String, List<CboApprovalFlowInsEntity>> flowinsListMap = cboApprovalFlowInsEntities.stream()
				.collect(Collectors.groupingBy(item -> item.getSourcetype()));
		// 所有需要更新异常状态的项目code
		Set<String> projectCodes = new HashSet<>();
		flowinsListMap.forEach((key, value) -> {
			// 根据不同的sourcetype查询不同的表获取项目code
			String sourceids = value.stream().map(map -> ConvertUtil.convertToString(map.getSourceid()))
					.collect(Collectors.joining(","));
			StringBufferProxy sql = new StringBufferProxy();
 			if (GpmProjectTaskFeedbackEntity.tableName.equals(key) || GpmProjectTaskCloseEntity.tableName.equals(key)) {
				// 先查询项目任务反馈记录，再查询项目任务，获取projectcode
				sql.appendSingle(" select distinct b.projectcode from {0} a left join " +
						"GpmProjectTask b on a.taskid = b.id where a.id in ({1}) ", key, sourceids);
			}  else if (GpmWfFormEntity.tableName.equals(key)) {
 				// 先查询SdWfForm表，找到立项变更记录，获取projectcode
				sql.appendSingle("select distinct history.projectcode from GPMWfForm form left join GpmProjectHistory history on " +
						" form.sourceid = history.id where form.id in ({0}) and form.sourcetype = '{1}' ", sourceids, GpmProjectHistoryEntity.tableName);
			} else {
				sql.appendSingle(" select projectcode from {0} where id in ({1}) ", key, sourceids);
			}

			List<Map<String, Object>> maps = this.selectExecute(sql.toString());
			maps.forEach(map -> projectCodes.add(ConvertUtil.convertToString(map.get("projectcode"))));
		});
		projectCodes.forEach(item -> {
			if (sdProjectListMap.get(item) != null && sdProjectListMap.get(item).size() > 0) {
				GpmProjectEntity gpmProjectEntity = sdProjectListMap.get(item).get(0);
				// 只更新异常状态为0或10的项目
				if (gpmProjectEntity.getAbnormalstate() == 0 || gpmProjectEntity.getAbnormalstate() == 10) {
					this.updateAbnormalInfo(gpmProjectEntity);
				}
			}
		});
	}
	/**
	 * @author: houyuhang
	 * @date: 2022-01-04
	 * @description: 更新异常状态和原因
	 * @modify:
	 */
	private void updateAbnormalInfo(GpmProjectEntity gpmProjectEntity) {
		Map<String, Object> updateMap = new HashMap<>();
		updateMap.put("id", gpmProjectEntity.getId());
		updateMap.put("abnormalstate", "15");
		this.update(updateMap);
	}
	/**
	 * @author: wudaliang zhangjunyao
	 * @date: 2021-07-08 2021-12-14
	 * @description: 即将超期项目、里程碑、任务，提前一天进行提醒。
	 * @return: com.topscomm.pub.vo.ResponseResult<java.lang.Object>
	 * @modify:
	 */
	@Override
	@Transactional
	public ResponseResult<Object> willExpireRemind() {
		try {
			StringBufferProxy sql = new StringBufferProxy();
			// 查询项目状态不是待立项、立项不通过、已结项的
			sql.appendSingle("enabled=1 and projectstate in (0,{0}) and state=9 and （to_char({1} - 1, 'yyyy-mm-dd')" +
					"= to_char(SYSDATE, 'yyyy-mm-dd') or to_char({1} - 3, 'yyyy-mm-dd')" +
					" = to_char(SYSDATE, 'yyyy-mm-dd'))", GpmSystemConst.ProjectOngoingState, GpmProjectEntity.FieldPlanenddate);
			List<GpmProjectEntity> overDueProjectEntities = this.queryByWhere(sql.toString());
			List<Map<String, Object>> appMap = new ArrayList<Map<String, Object>>();
			List<Map<String, Object>> sysMap = new ArrayList<Map<String, Object>>();
			// 发送消息内容
			String[] title = {"通用项目管理超期预警", "通用项目管理里程碑超期预警", "通用项目管理任务超期预警"};
			String[] remindContent = {"明天即将超期", "三天后即将超期"};
			Date date = new Date();
			SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
			String format = simpleDateFormat.format(date);
			Date currentDate = simpleDateFormat.parse(format);
			if (!org.springframework.util.CollectionUtils.isEmpty(overDueProjectEntities)) {
				for (GpmProjectEntity overDueProjectEntity : overDueProjectEntities) {
					Date planEndDate = overDueProjectEntity.getPlanenddate();
					String content = "【" + overDueProjectEntity.getProjectname() + "】";
					// 若三天后超期则如下配置消息内容
					if (planEndDate.getTime() - currentDate.getTime() == DAY_MILLSECONDS) {
						content = content + remindContent[1] + "，项目编号为：" + overDueProjectEntity.getProjectcode() + "。";
					} else {
						content = content + remindContent[0] + "，项目编号为：" + overDueProjectEntity.getProjectcode() + "。";
					}
					// 插入App消息
					Map<String, Object> projectappmap = this.insertMessageApp(overDueProjectEntity.getProjectmanagercode(),
							title[0], content, overDueProjectEntity.getId(), PROJECTSOURCETYPE, 0);
					appMap.add(projectappmap);
					// 插入系统消息
					Map<String, Object> projectsysmap = this.insertMessageSys(overDueProjectEntity.getProjectmanagercode(),
							overDueProjectEntity.getProjectmanager(), title[0], content, overDueProjectEntity.getId(), PROJECTSOURCETYPE);
					sysMap.add(projectsysmap);
				}
			}
			// 查询是否即将里程碑超期
			sql.clear();
			sql.appendSingle(" milepoststate = 0 and enabled = 1 and (to_char({0} - 1, 'yyyy-mm-dd') = to_char(sysdate, 'yyyy-mm-dd')" +
							" or to_char({0} - 3, 'yyyy-mm-dd') = to_char(sysdate, 'yyyy-mm-dd'))",
					GpmProjectMilepostEntity.FieldPlanfinishtime);
			List<GpmProjectMilepostEntity> overDueProjectMilepostEntities = gpmProjectMilepostService.queryByWhere(sql.toString());
			if (!org.springframework.util.CollectionUtils.isEmpty(overDueProjectMilepostEntities)) {
				// 查询里程碑对应项目
				String projectCodes = overDueProjectMilepostEntities.stream().map(entity -> entity.getProjectcode())
						.collect(Collectors.joining("','", "'", "'"));
				sql.clear();
				sql.appendSingle("projectcode in ({0})", projectCodes);
				List<GpmProjectEntity> projectEntities = this.queryByWhere(sql.toString());
				Map<String, GpmProjectEntity> projectMap = projectEntities.stream().collect(Collectors.toMap(
						GpmProjectEntity::getProjectcode, item -> item));
				for (GpmProjectMilepostEntity overDueProjectMilepostEntity : overDueProjectMilepostEntities) {
					Date planFinishDate = overDueProjectMilepostEntity.getPlanfinishtime();
					String milepostcontent = "【" + projectMap.get(overDueProjectMilepostEntity.getProjectcode()).getProjectname() + "】的“" +
							overDueProjectMilepostEntity.getMilepostname() + "”里程碑，";
					// 若三天后超期则如下配置消息内容
					if (planFinishDate.getTime() - currentDate.getTime() == DAY_MILLSECONDS) {
						milepostcontent = milepostcontent + remindContent[1] + "。";
					} else {
						milepostcontent = milepostcontent + remindContent[0] + "。";
					}
					// 插入App消息
					Map<String, Object> milepostappmap = this.insertMessageApp(overDueProjectMilepostEntity.getResponsiblecode(),
							title[1], milepostcontent, projectMap.get(overDueProjectMilepostEntity.getProjectcode()).getId(), GpmProjectMilepostEntity.tableName,
							0);
					appMap.add(milepostappmap);
					// 插入系统消息
					Map<String, Object> mielpostsysmap = this.insertMessageSys(overDueProjectMilepostEntity.getResponsiblecode(),
							overDueProjectMilepostEntity.getResponsible(), title[1], milepostcontent,
							projectMap.get(overDueProjectMilepostEntity.getProjectcode()).getId(), GpmProjectMilepostEntity.tableName);
					sysMap.add(mielpostsysmap);
				}
			}
			// 查询是否即将任务超期
			sql.clear();
			sql.appendSingle(" taskstate in (0,1) and enabled=1 and (to_char({0} - 1, 'yyyy-mm-dd') = to_char(sysdate, 'yyyy-mm-dd')" +
							" or to_char({0} - 3, 'yyyy-mm-dd') = to_char(sysdate, 'yyyy-mm-dd'))",
					GpmProjectTaskEntity.FieldPlanenddate);
			List<GpmProjectTaskEntity> overDueProjectTaskEntities = gpmProjectTaskService.queryByWhere(sql.toString());
			if (!org.springframework.util.CollectionUtils.isEmpty(overDueProjectTaskEntities)) {
				// 查询里程碑对应项目
				String projectCodes = overDueProjectTaskEntities.stream().map(entity -> entity.getProjectcode())
						.collect(Collectors.joining("','", "'", "'"));
				sql.clear();
				sql.appendSingle("projectcode in ({0})", projectCodes);
				List<GpmProjectEntity> projectEntities = this.queryByWhere(sql.toString());
				Map<String, GpmProjectEntity> projectMap = projectEntities.stream().collect(Collectors.toMap(
						GpmProjectEntity::getProjectcode, sdProjectEntity -> sdProjectEntity));
				for (GpmProjectTaskEntity overDueProjectTaskEntity : overDueProjectTaskEntities) {
					Date planEndDate = overDueProjectTaskEntity.getPlanenddate();
					String taskResponsibleCode = overDueProjectTaskEntity.getResponsiblecode();
					GpmProjectEntity projectEntity = projectMap.get(overDueProjectTaskEntity.getProjectcode());
					String taskcontent = "【" + projectEntity.getProjectname() + "】的“" +
							overDueProjectTaskEntity.getTaskname() + "”任务，";
					// 若三天后超期则如下配置消息内容
					if (planEndDate.getTime() - currentDate.getTime() == DAY_MILLSECONDS) {
						taskcontent = taskcontent + remindContent[1] + "。";
					} else {
						taskcontent = taskcontent + remindContent[0] + "。";
					}
					// 通知任务负责人
					// 插入App消息
					Map<String, Object> taskappmap = this.insertMessageApp(taskResponsibleCode,
							title[2], taskcontent, projectMap.get(overDueProjectTaskEntity.getProjectcode()).getId(), GpmProjectTaskEntity.tableName, 0);
					appMap.add(taskappmap);
					// 插入系统消息
					Map<String, Object> tasksysmap = this.insertMessageSys(taskResponsibleCode,
							overDueProjectTaskEntity.getResponsible(), title[2], taskcontent, projectMap.get(overDueProjectTaskEntity.getProjectcode()).getId(),
							GpmProjectTaskEntity.tableName);
					sysMap.add(tasksysmap);
					// 获取里程碑责任人
					sql.clear();
					sql.appendSingle("id = {0} and enabled = '1'", overDueProjectTaskEntity.getMilepostcode());
					List<GpmProjectMilepostEntity> milepostEntities = gpmProjectMilepostService.queryByWhere(sql.toString());
					if (!org.springframework.util.CollectionUtils.isEmpty(milepostEntities)) {
						String milepostResponsibleCode = milepostEntities.get(0).getResponsiblecode();
						// 若里程碑责任人和任务责任人不是同一个人则需要通知里程碑责任人
						if (!milepostResponsibleCode.equals(taskResponsibleCode)) {
							// 插入App消息
							taskappmap = this.insertMessageApp(milepostResponsibleCode, title[2], taskcontent,
									projectMap.get(overDueProjectTaskEntity.getProjectcode()).getId(), GpmProjectTaskEntity.tableName, 0);
							appMap.add(taskappmap);
							// 插入系统消息
							tasksysmap = this.insertMessageSys(milepostResponsibleCode, milepostEntities.get(0).getResponsible(),
									title[2], taskcontent, projectMap.get(overDueProjectTaskEntity.getProjectcode()).getId(), GpmProjectTaskEntity.tableName);
							sysMap.add(tasksysmap);
						}
					}
					if (!org.springframework.util.CollectionUtils.isEmpty(milepostEntities)) {
						// 若项目经理和任务责任人不是同一个人，里程碑责任人和项目经理也不是同一个人时则需要通知项目经理
						String milepostResponsibleCode = milepostEntities.get(0).getResponsiblecode();
						if (!taskResponsibleCode.equals(projectEntity.getProjectmanagercode()) && !milepostResponsibleCode
								.equals(projectEntity.getProjectmanagercode())) {
							// 插入App消息
							taskappmap = this.insertMessageApp(projectEntity.getProjectmanagercode(), title[2], taskcontent,
									projectMap.get(overDueProjectTaskEntity.getProjectcode()).getId(), GpmProjectTaskEntity.tableName, 0);
							appMap.add(taskappmap);
							// 插入系统消息
							tasksysmap = this.insertMessageSys(projectEntity.getProjectmanagercode(), projectEntity.getProjectmanager(),
									title[2], taskcontent, projectMap.get(overDueProjectTaskEntity.getProjectcode()).getId(), GpmProjectTaskEntity.tableName);
							sysMap.add(tasksysmap);
						}
					} else {
						// 若没有里程碑（历史数据问题）则直接比较任务责任人和项目经理
						if (!taskResponsibleCode.equals(projectEntity.getProjectmanagercode())) {
							// 插入App消息
							taskappmap = this.insertMessageApp(projectEntity.getProjectmanagercode(), title[2], taskcontent,
									projectMap.get(overDueProjectTaskEntity.getProjectcode()).getId(), GpmProjectTaskEntity.tableName, 0);
							appMap.add(taskappmap);
							// 插入系统消息
							tasksysmap = this.insertMessageSys(projectEntity.getProjectmanagercode(), projectEntity.getProjectmanager(),
									title[2], taskcontent, projectMap.get(overDueProjectTaskEntity.getProjectcode()).getId(), GpmProjectTaskEntity.tableName);
							sysMap.add(tasksysmap);
						}
					}
				}
			}
			cboMessageAppService.insertList(appMap);
			cboMessageSysService.insertList(sysMap);
			return ResponseResult.ok("操作成功");
		} catch (Exception ex) {
			logger.info("日期转换出错，异常类：{}，堆栈：{}",ex.getClass().getSimpleName(),ex.fillInStackTrace());
			return ResponseResult.error("请联系管理员!");
		}
	}
	/**
	 * @author: wudaliang
	 * @date: 2021-07-08
	 * @description: 插入App消息
	 * @return: java.util.Map<java.lang.String, java.lang.Object>
	 * @modify:
	 */
	public Map<String, Object> insertMessageApp(String usercode,String extendfield1,String content,long sourceid,String sourcetype,int sendtype) {
		HashMap<String, Object> map = new HashMap<>();
		map.put("usercode", usercode);
		map.put("extendfield1", extendfield1);
		map.put("content", content);
		map.put("sourceid", sourceid);
		map.put("sourcetype", sourcetype);
		map.put("sendtype", sendtype);
		return map;
	}


	public Map<String, Object> insertMessageAppForMsg(String receivercode,String receivername,String extendfield1,String content,long sourceid,String sourcetype,int sendtype) {
		HashMap<String, Object> map = new HashMap<>();
//		map.put("usercode", usercode);
		map.put("receivercode", receivercode);
		map.put("receivername", receivername);
		map.put("extendfield1", extendfield1);
		map.put("content", content);
		map.put("sourceid", sourceid);
		map.put("sourcetype", sourcetype);
		map.put("sendtype", sendtype);
		return map;
	}

	/**
	 * @author: wudaliang
	 * @date: 2021-07-08
	 * @description: 插入系统消息
	 * @return: java.util.Map<java.lang.String, java.lang.Object>
	 * @modify:
	 */
	public Map<String, Object> insertMessageSys(String receivercode,String receivername,String subject,String content,long sourceid,String sourcetype) {
		HashMap<String, Object> map = new HashMap<>();
		map.put("receivercode", receivercode);
		map.put("receivername", receivername);
		map.put("subject", subject);
		map.put("content", content);
		map.put("sourceid", sourceid);
		map.put("sourcetype", sourcetype);
		return map;
	}
	/**
	 * @author: houyuhang
	 * @date: 2022-01-07
	 * @description: 根据机会点编号获取销售项目编号
	 * @modify:
	 */
	public Map<String,Object> mpmProjectCode(Map<String, Object> paraMap) {
		String chanceclue = ConvertUtil.convertToString(paraMap.get("chanceclue"));
		String[] split = chanceclue.split(",");
		String tempChanceclue = Arrays.stream(split).map(item -> "'" + item + "'").collect(Collectors.joining(","));
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" chanceclue in ({0})",tempChanceclue);
		List<Map<String,Object>> res = mpmProjectService.queryMpmProjectCodeByChanceclue(sql.toString());
		String projectcode = "";
		if(res.size() > 0) {
			projectcode = res.stream().map(item -> ConvertUtil.convertToString(item.get("projectcode"))).collect(Collectors.joining(","));
		}
		Map<String,Object> dataMap = new HashMap<>();
		dataMap.put("projectcode",projectcode);
		return dataMap;
	}
	@Override
	public void setDispFields(Map<String, Object> mapRow, DatacodeCache datacodeCache) {
		super.setDispFields(mapRow, datacodeCache);
		String temp;
		if (mapRow.get("whetherhistorydata") != null) {
			temp = mapRow.get("whetherhistorydata").toString();
			mapRow.put("dispwhetherhistorydata", datacodeCache.getValueDynamic("CboYesNo", temp, "code", "name"));
		} else {
			mapRow.put("dispwhetherhistorydata","否");
		}
		if (mapRow.get("approvalprojecttype") != null) {
			temp = mapRow.get("approvalprojecttype").toString();
			mapRow.put("dispapprovalprojecttype", datacodeCache.getValueDynamic("GpmApprovalprojecttypeList", temp, "code", "name"));
		}
		// 拼接字符串 项目经理[项目经理工号] 部门
		if(mapRow.get("projectmanagercode") != null && mapRow.get("deptname") != null)
		{
			temp = ConvertUtil.convertToString(mapRow.get("projectmanagercode"));
			String deptcommoncode1 = ConvertUtil.convertToString(mapRow.get("deptcommoncode1"));
			mapRow.put("dispprojectmanagercodeanddeptnamemobile", datacodeCache.getValueDynamic("CboUser", temp, "code", "name")+"["
					+ temp + "]-" + datacodeCache.getValueDynamic("DeptCommonCode", deptcommoncode1, "code", "name"));
		}
		// 拼接字符串 计划开始日期-计划结束日期
		if(mapRow.get("planstartdate") != null && mapRow.get("planenddate") != null)
		{
			SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
			String planstartdate = simpleDateFormat.format(mapRow.get("planstartdate"));
			String planenddate = simpleDateFormat.format(mapRow.get("planenddate"));
			mapRow.put("planstartdateandplanenddatemobile", planstartdate + "至" + planenddate);
		}
		// 拼接字符串 督办情况
		if(mapRow.get("supervisecodelist") != null && mapRow.get("supervisestatelist") != null) {
			StringBuffer stringBuffer = new StringBuffer();
			String[] supervisecodesplit = ConvertUtil.convertToString(mapRow.get("supervisecodelist")).split(",");
			String[] supervisestatesplit = ConvertUtil.convertToString(mapRow.get("supervisestatelist")).split(",");
			if(supervisecodesplit.length>3) {
				for(int i=0;i<3;i++) {
					stringBuffer.append(supervisecodesplit[i] + "[" + datacodeCache.getValueDynamic("GpmSuperviseState", supervisestatesplit[i], "code", "name") + "]\n");
				}
				stringBuffer.append("...\n");
			} else {
				for (int i = 0; i < supervisecodesplit.length; i++) {
					stringBuffer.append(supervisecodesplit[i] + "[" + datacodeCache.getValueDynamic("GpmSuperviseState", supervisestatesplit[i], "code", "name") + "]\n");
				}
			}
			String str = stringBuffer.toString();
			str = str.substring(0,str.length()-1);
			mapRow.put("superviselistmobile", str);
		}
		if (mapRow.get("ourprocductfund") != null) {
			temp = mapRow.get("ourprocductfund").toString();
			mapRow.put("dispourprocductfund",temp+"万元");
		}
		if (mapRow.get("bidcycle") != null) {
			temp = mapRow.get("bidcycle").toString();
			mapRow.put("dispbidcycle",temp+"天");
		}
	}
	/**
	 * @author: zhangjunyao
	 * @date: 2022-01-18
	 * @description: 判断决策组会签节点是否有人退回
	 * @modify:
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean ifApprovalBack(String projectId) {
		boolean ifApprovalBack = false;
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle("sourceid = '{0}' and sourcetype = '{1}'", projectId, GpmProjectEntity.tableName);
		List<GpmWfFormEntity> sdWfFormEntities = gpmWfFormService.queryByWhere(sql.toString());
		if (!CollectionUtils.isEmpty((sdWfFormEntities))) {
			GpmWfFormEntity gpmWfFormEntity = sdWfFormEntities.get(0);
			sql.clear();
			sql.appendSingle("nodeid = (select id from {0} where {1} like '%ifApproveBack%') and sourceid = {2} and sourcetype = '{3}' and state = '3'",
					CboApprovalNodeEntity.tableName, CboApprovalNodeEntity.FieldApprovalparam, gpmWfFormEntity.getId(), GpmWfFormEntity.tableName);
			List<CboApprovalNodeInsEntity> nodeInsEntities = cboApprovalNodeInsService.queryByWhere(sql.toString());
			if (!CollectionUtils.isEmpty(nodeInsEntities)) {
				ifApprovalBack = true;
			}
		}
		return ifApprovalBack;
	}

	/**
	 * @author: zhangjunyao
	 * @date: 2022-01-18
	 * @description: 重写立项取消审批方法，修改sourcetype获取逻辑
	 * @modify:
	 */
	@Transactional(rollbackFor = Exception.class)
	public void executeDelApprove(String id) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" sourceid = '{0}' and sourcetype = '{1}' and {2} = '{3}' ", id, GpmProjectEntity.tableName,
				GpmWfFormEntity.FieldBusinesstype, GpmSystemConst.SdApprovalCategory.SdProjectApproval);
		List<GpmWfFormEntity> sdWfFormEntities = gpmWfFormService.queryByWhere(sql.toString());
		gpmWfFormService.deleteByWhere(sql.toString());
		if (!CollectionUtils.isEmpty(sdWfFormEntities)) {
			GpmWfFormEntity gpmWfFormEntity = sdWfFormEntities.get(0);
			sql.clear();
			sql.appendSingle(" sourceid = '{0}' and sourcetype='{1}' ", gpmWfFormEntity.getId(), GpmWfFormEntity.tableName);
			cboApprovalNodeInsService.deleteByWhere(sql.toString());
			cboApprovalFlowInsService.deleteByWhere(sql.toString());
			Map<String, Object> map_update = new HashMap();
			map_update.put("id", id);
			map_update.put("state", TapSystemConst.TapApprovalBillStateEnum.Open);
			map_update.put("submitdate", null);
			this.update(map_update);
		}
	}

	/**
	 * @param billEntity
	 * @param nodeIns
	 * @author: zhangjunyao
	 * @date: 2022年1月18日
	 * @return_type: void
	 * @description: 重写afterApprove方法，决策组会签节点有人退回时发送消息提醒
	 * @modify:
	 */
	protected void afterDecisionApprove(TapEntity billEntity, CboApprovalNodeInsEntity nodeIns, CboApprovalNodeEntity node, SessionUserBean sessionUserBean) {
		String mark = node.getApprovalparam();
		int state = nodeIns.getState();
		if (!StringUtil.isEmpty(mark) && mark.contains("ifApproveBack") && state == TapSystemConst.TapApprovalNodeStateEnum.UnApproved) {
			String sourcetye = nodeIns.getSourcetype() + "-ifApproveBack";
			GpmWfFormEntity gpmWfFormEntity = (GpmWfFormEntity) billEntity;
			GpmProjectEntity projectEntity = this.queryById( ConvertUtil.convertToString(gpmWfFormEntity.getSourceid()));
			// 消息标题和内容
			String title = "【" + projectEntity.getProjectname() + "项目】";
			String content = "【" + projectEntity.getProjectname() + "项目】：" + "在" + nodeIns.getExtendfield2() + "节点中，审批人" +
					sessionUserBean.getUser().getName() + "不同意此项目审批通过。您可前往立项详情页选择“取消审批”。";
			// 系统消息
			Map<String, Object> sysMessage = insertMessageSys(projectEntity.getProjectmanagercode(), projectEntity.getProjectmanager(),
					title, content, nodeIns.getSourceid(), sourcetye);
			sysMessage.put("messagetype", MisSystemConst.MobileMessageType.OTHER_TYPE);
//			cboMessageSysService.insertMap(sysMessage);
			sendMessageService.sendSysMessage(sysMessage);
			// App消息
			Map<String, Object> appMessage = insertMessageAppForMsg(projectEntity.getProjectmanagercode(),projectEntity.getProjectmanager(), title, content,
					nodeIns.getSourceid(), sourcetye, 0);
//			cboMessageAppService.insertMap(appMessage);
			sendMessageService.sendSysMessage(appMessage);
		}
	}

	@Override
	public void sendMessagetoSdLeader(String projectname, String projectlevel, String usercodes,String sourcetype,long sourceid) {
		String title = "通用项目立项提醒";
		projectname = projectname.endsWith("项目") ? projectname : (projectname + "项目");
		String content = "【"+projectlevel+"级"+projectname+"】立项申请已在“省总审批”阶段通过，请登录通用项目系统查阅";
		List<CboUserEntity> cboUserEntities = cboUserService.queryByWhere("code in ("+usercodes+")");
		List<Map<String, Object>> appList = new ArrayList<>(), sysList = new ArrayList<>();
		for(CboUserEntity userEntity:cboUserEntities) {
			Map<String,Object> appMap = MessageUtil.createMessageAppMapV1(userEntity.getCode(), userEntity.getName(), title, content, sourceid,
					sourcetype, 0);
			appMap.put("messagetype", MisSystemConst.MobileMessageType.OTHER_TYPE);
			Map<String,Object> sysMap = MessageUtil.createMessageSysMapV1(userEntity.getCode(), userEntity.getName(), title, content,
					sourceid, sourcetype);
			sysMap.put("messagetype", MisSystemConst.MobileMessageType.OTHER_TYPE);
			appList.add(appMap);
			sysList.add(sysMap);
		}
		if(appList.size()>0) {
//			cboMessageAppService.insertList(appList);
//			cboMessageSysService.insertList(sysList);
			sendMessageService.sendSysMessage(sysList);
			sendMessageService.sendAppMessage(appList);
		}

	}

	public HashMap<String,String> getProjectState(List<Map<String,Object>> tempList) {
		HashMap<String,String> result = new HashMap<String, String>();
		if(tempList==null || tempList.size() == 0) {
			return result;
		}
		String ids = tempList.stream().filter(m->"7".equals(ConvertUtil.convertToString(m.get("projectstate")))).map(m->ConvertUtil.convertToString(m.get("projectcode"))).collect(Collectors.joining("','","'","'"));
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle("projectcode in ({0}) and enabled = 1 order by planfinishtime asc",ids);
		List<GpmProjectMilepostEntity> milepostEntities = gpmProjectMilepostService.queryByWhere(sql.toString());
		if(milepostEntities== null || milepostEntities.size() == 0) {
			return result;
		}
		Map<String,List<GpmProjectMilepostEntity>> tempMap = milepostEntities.stream().collect(Collectors.groupingBy(GpmProjectMilepostEntity::getProjectcode));
		tempMap.forEach((key,value)->{
			int reachCount = 0;
			for (int i = 0; i < value.size(); i++) {
				GpmProjectMilepostEntity gpmProjectMilepostEntity = value.get(i);
				//判断里程状态，满足条件跳出循环
				if(gpmProjectMilepostEntity.getMilepoststate() == 0 ){
					reachCount = i + 1;
					break;
				}
			}
			String tempresult =  datacodeCache.getValueDynamic("GpmProjectState", "7", "code", "name");
			//重新定义项目状态
			sql.clear();
			// 若里程碑都已完成则显示“复盘阶段”
			if (reachCount == 0) {
				sql.appendSingle("复盘阶段");
			} else {
				sql.appendSingle("{0}{1}/{2}", tempresult, reachCount, value.size());
			}
			tempresult = sql.toString();
			result.put(key,tempresult);
		});
		return result;
	}

	@Override
	@Transactional
	public void changeOwner(Map<String, Object> paraMap) {
		// 更新对应的信息
		String id = ConvertUtil.convertToString(paraMap.get("id"));
		String oldprojectmanagercode = ConvertUtil.convertToString(paraMap.get("oldprojectmanagercode"));
		List<String> updateList = new ArrayList<>();
		updateList.add(GpmProjectEntity.FieldProjectmanager);
		updateList.add(GpmProjectEntity.FieldProjectmanagercode);
		updateList.add(GpmProjectEntity.FieldDeptcode);
		updateList.add(GpmProjectEntity.FieldDeptname);
		GpmProjectEntity gpmProjectEntity = new GpmProjectEntity();
		gpmProjectEntity.convertFromMap(paraMap);
		this.updateFields(gpmProjectEntity,updateList);
		// 更新历史表信息
		StringBufferProxy sql = new StringBufferProxy();
		sql.clear();
		sql.appendSingle("projectid = {0} order by id desc",id);
		List<GpmProjectHistoryEntity> sdProjectHistoryEntities = gpmProjectHistoryService.queryByWhere(sql.toString());
		if(sdProjectHistoryEntities.size()>0) {
			GpmProjectHistoryEntity historyEntity = sdProjectHistoryEntities.get(0);
			historyEntity.setProjectmanagercode(gpmProjectEntity.getProjectmanagercode());
			historyEntity.setProjectmanager(gpmProjectEntity.getProjectmanager());
			historyEntity.setDeptname(gpmProjectEntity.getDeptname());
			historyEntity.setDeptcode(gpmProjectEntity.getDeptcode());
			gpmProjectHistoryService.updateFields(historyEntity,updateList);
		}
		// 修改项目任命表项目经理姓名、工号字段
		this.changeSdAppointment(gpmProjectEntity.getProjectcode(), gpmProjectEntity.getProjectmanagercode(), gpmProjectEntity.getProjectmanager());		// 修改项目任命详情表项目经理姓名、工号字段
		this.changeSdTeam(gpmProjectEntity.getProjectcode(), gpmProjectEntity.getProjectmanagercode(), gpmProjectEntity.getProjectmanager());
		// 修改项目相关方项目经理,将原项目经理的enabled置为0，创建新的项目经理
		// 变更相关方中的项目经理
		sql.clear();
		sql.appendSingle("grouprolecode = '{0}' and projectcode = '{1}' and enabled = 1","pm", gpmProjectEntity.getProjectcode());
		List<GpmProjectStakeholderEntity> stakeholderEntities = gpmProjectStakeholderService.queryByWhere(sql.toString());
		if(stakeholderEntities.size()>0) {
			GpmProjectStakeholderEntity newEntity = new GpmProjectStakeholderEntity();
			newEntity.convertFromMap(stakeholderEntities.get(0).convertToMap());
			newEntity.setId(0L);
			newEntity.setUsercode(gpmProjectEntity.getProjectmanagercode());
			newEntity.setUsername(gpmProjectEntity.getProjectmanager());
			GpmProjectStakeholderEntity stakeholderEntity = stakeholderEntities.get(0);
			stakeholderEntity.setEnabled(0);
			gpmProjectStakeholderService.updateEntity(stakeholderEntity);
			gpmProjectStakeholderService.insert(newEntity);
		}
		sql.clear();
		sql.appendSingle("update {0} set projectmanagercode = '{1}', projectmanagername = '{2}' where projectcode = '{3}' and enabled = 1",
				GpmProjectStakeholderEntity.tableName, gpmProjectEntity.getProjectmanagercode(), gpmProjectEntity.getProjectmanager(), gpmProjectEntity.getProjectcode());
		gpmProjectStakeholderService.updateExecute(sql.toString());
		this.changeApprovalNodeManager(oldprojectmanagercode, gpmProjectEntity.getProjectmanagercode(), gpmProjectEntity.getProjectcode(),id);
		// 修改里程碑责任人
		this.changeMilepost(gpmProjectEntity.getProjectcode(),oldprojectmanagercode, gpmProjectEntity.getProjectmanagercode(), gpmProjectEntity.getProjectmanager());
		//修改任务责任人信息
		this.changeTask(gpmProjectEntity.getProjectcode(),oldprojectmanagercode, gpmProjectEntity.getProjectmanagercode(), gpmProjectEntity.getProjectmanager());
		//修改项目风险、问题、需求项目经理工号和姓名
		this.changeManagercode(gpmProjectEntity.getProjectcode(), gpmProjectEntity.getProjectmanagercode(), gpmProjectEntity.getProjectmanager());

	}

	private void changeApprovalNodeManager(String oldprojectmanagercode,String projectmanagercode,String projectcode,String projectid) {
		ICboApprovalNodeInsService cboApprovalNodeInsService = (CboApprovalNodeInsService) SpringUtil.getBean("cboApprovalNodeInsService");
		// 更改审批历史
		Map<String,Object> wfFormUpdateMap = new HashMap<String,Object>();
		StringBufferProxy sql = new StringBufferProxy();
		String[] splitSourcetype = GpmSystemConst.sdSourcetype.split(",");
		sql.appendSingle("code = '{0}'",projectmanagercode);
		List<CboUserEntity> cboUserEntities = cboUserService.queryByWhere(sql.toString());
		if(cboUserEntities.size()==0) {
			return;
		}
		long newuserid = cboUserEntities.get(0).getId();
		List<BasicEntity> basicEntities = new ArrayList<>();
		for(String sourcetype:splitSourcetype) {
			sql.clear();
			if("GpmProject".equals(sourcetype)) {
				sourcetype = GpmWfFormEntity.tableName;
				sql.appendSingle(" finalsourcetype = '{0}' and finalsourceid = {1} ", sourcetype,projectid);
			} else if (GpmProjectTaskCloseEntity.tableName.equals(sourcetype) || GpmProjectTaskFeedbackEntity.tableName.equals(sourcetype)) {
				sql.appendSingle("enabled = 1 and taskid in (select id from GPMProjectTask where enabled = 1 and projectcode = '{0}')",projectcode);
			} else {
				sql.appendSingle(" enabled = 1 and projectcode = '{0}' ", projectcode);
			}
			List<Map<String,Object>> res = this.selectExecute("select * from " + sourcetype + " where " + sql);
			String id = res.stream().map(item -> ConvertUtil.convertToString(item.get("id"))).collect(Collectors.joining(","));
			if(!StringUtil.isEmpty(id)) {
				// 查找审批流程下所有需要原项目经理审批的节点，将办理人改为新项目经理
				sql.clear();
				sql.appendSingle(" sourceid in ({0}) and sourcetype = '{1}' and state = '1' and approvaluserid in (select id from CboUser where code =  '{2}') ",id,sourcetype,oldprojectmanagercode);
				List<CboApprovalNodeInsEntity> cboApprovalNodeInsEntities = cboApprovalNodeInsService.queryByWhere(sql.toString());

				cboApprovalNodeInsEntities.forEach(cboApprovalNodeInsEntity -> {
					cboApprovalNodeInsEntity.setApprovaluserid(newuserid);
					basicEntities.add(cboApprovalNodeInsEntity);
				});
			}
		}
		if(basicEntities.size()>0) {
			cboApprovalNodeInsService.updateBatch(basicEntities);
		}
	}

	// 修改里程碑及任务责任人信息
	private void changeMilepost(String projectcode,String oldprojectmanagercode,String projectmanagercode,String projectmanager) {
		// 修改里程碑及任务责任人
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle("projectcode = '{0}' and enabled = 1 and responsiblecode = '{1}' ",
				projectcode,oldprojectmanagercode);
		// 获取项目中由离职人员负责的里程碑及任务
		List<GpmProjectMilepostEntity> gpmProjectMilepostEntityList = gpmProjectMilepostService.queryByWhere(sql.toString());
		List<BasicEntity> basicEntities = new ArrayList<>();
		for(GpmProjectMilepostEntity gpmProjectMilepostEntity : gpmProjectMilepostEntityList) {
			gpmProjectMilepostEntity.setResponsiblecode(projectmanagercode);
			gpmProjectMilepostEntity.setResponsible(projectmanager);
			basicEntities.add(gpmProjectMilepostEntity);
		}
		// 将里程碑及任务的责任人改为交接人
		gpmProjectMilepostService.updateBatch(basicEntities);
		// 不存在里程碑及任务责任人发生变化的情况
		if(gpmProjectMilepostEntityList.size() == 0) {
			return;
		}
		// 存在里程碑及任务责任人发生变化的情况
		List<BasicEntity> updateEntity = new ArrayList<>();
		sql.clear();
		// 查询里程碑及任务下处于里程碑及任务责任人审批阶段的任务反馈和任务关闭流程
		String milepostId = gpmProjectMilepostEntityList.stream().map(item -> ConvertUtil.convertToString(item.getId()))
				.collect(Collectors.joining("','","'","'"));
		// 任务反馈流程
		sql.appendSingle("GPMPROJECTMILEPOST.ID IN ({0}) and GpmProjectTaskFeedback.STATE = 1 ",milepostId);
		List<Map<String,Object>> taskFeedbackApprovalList = gpmProjectMilepostService.queryMapByWhere(sql.toString(),"queryTaskFeedback");
		if(taskFeedbackApprovalList.size()>0) {
			for (Map<String, Object> taskFeedbackApprovalMap : taskFeedbackApprovalList) {
				// 查询人员code对应的id
				sql.clear();
				sql.appendSingle(" code = '{0}' ", ConvertUtil.convertToString(taskFeedbackApprovalMap.get("responsiblecode")));
				CboUserEntity cboUserEntity = cboUserService.queryObjectByWhere(sql.toString());
				// 查询里程碑及任务责任人正在审批的流程
				sql.clear();
				sql.appendSingle("SELECT CBOAPPROVALNODEINS.* FROM CBOAPPROVALNODEINS INNER JOIN CBOAPPROVALNODE " +
								"ON CBOAPPROVALNODEINS.NODEID = CBOAPPROVALNODE.ID WHERE CBOAPPROVALNODEINS.SOURCEID = '{0}' " +
								"AND  CBOAPPROVALNODEINS.SOURCETYPE = '{1}' AND STATE = 1 AND " +
								"CBOAPPROVALNODE.APPROVALPARAM LIKE '%milepostcheckfeedback%'",taskFeedbackApprovalMap.get("sourceid"),
						GpmProjectTaskFeedbackEntity.tableName);
				List<Map<String,Object>> feedbackList = cboApprovalNodeInsService.selectExecute(sql.toString());
				// 存在任务反馈流程正处于里程碑及任务责任人审批节点的流程，将里程碑及任务责任人进行更换
				if(feedbackList.size() > 0) {
					CboApprovalNodeInsEntity cboApprovalNodeInsEntity = new CboApprovalNodeInsEntity();
					cboApprovalNodeInsEntity.convertFromMap(feedbackList.get(0));
					cboApprovalNodeInsEntity.setApprovaluserid(cboUserEntity.getId());
					updateEntity.add(cboApprovalNodeInsEntity);
				}
			}
		}
		// 任务关闭流程
		sql.clear();
		sql.appendSingle("GpmProjectMilepost.ID IN ({0}) and GpmPROJECTTASKCLOSE.STATE = 1 ",milepostId);
		List<Map<String,Object>> taskCloseApprovalList = gpmProjectMilepostService.queryMapByWhere(sql.toString(),"queryTaskClose");
		if(taskCloseApprovalList.size() > 0) {
			for (Map<String, Object> taskCloseApprovalMap : taskCloseApprovalList) {
				// 查询人员code对应的id
				sql.clear();
				sql.appendSingle(" code = '{0}' ", ConvertUtil.convertToString(taskCloseApprovalMap.get("responsiblecode")));
				CboUserEntity cboUserEntity = cboUserService.queryObjectByWhere(sql.toString());
				// 查询里程碑及任务责任人正在审批的流程
				sql.clear();
				sql.appendSingle("SELECT CBOAPPROVALNODEINS.* FROM CBOAPPROVALNODEINS INNER JOIN CBOAPPROVALNODE " +
								"ON CBOAPPROVALNODEINS.NODEID = CBOAPPROVALNODE.ID WHERE CBOAPPROVALNODEINS.SOURCEID = '{0}' " +
								"AND  CBOAPPROVALNODEINS.SOURCETYPE = '{1}' AND STATE = 1 AND " +
								"CBOAPPROVALNODE.APPROVALPARAM LIKE '%milepostcheckclose%'",taskCloseApprovalMap.get("sourceid"),
						GpmProjectTaskCloseEntity.tableName);
				List<Map<String,Object>> closeList = cboApprovalNodeInsService.selectExecute(sql.toString());
				// 存在任务关闭流程正处于里程碑及任务责任人审批节点的流程，将里程碑及任务责任人进行更换
				if(closeList.size() > 0) {
					CboApprovalNodeInsEntity cboApprovalNodeInsEntity = new CboApprovalNodeInsEntity();
					cboApprovalNodeInsEntity.convertFromMap(closeList.get(0));
					cboApprovalNodeInsEntity.setApprovaluserid(cboUserEntity.getId());
					updateEntity.add(cboApprovalNodeInsEntity);
				}
			}
		}
		// 更新任务反馈和任务关闭的里程碑及任务责任人节点办理人
		cboApprovalNodeInsService.updateBatch(updateEntity);
	}
	// 修改任务责任人信息
	private void changeTask(String projectcode,String oldprojectmanagercode,String projectmanagercode,String projectmanager ) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle("projectcode = '{0}' and enabled = 1 and responsiblecode = '{1}'",
				projectcode,oldprojectmanagercode);
		List<GpmProjectTaskEntity> gpmProjectTaskEntityList = gpmProjectTaskService.queryByWhere(sql.toString());
		List<BasicEntity> basicEntities = new ArrayList<>();
		for(GpmProjectTaskEntity mpmProjectTaskEntity : gpmProjectTaskEntityList) {
			mpmProjectTaskEntity.setResponsiblecode(projectmanagercode);
			mpmProjectTaskEntity.setResponsible(projectmanager);
			basicEntities.add(mpmProjectTaskEntity);
		}
		gpmProjectTaskService.updateBatch(basicEntities);
	}

	// 修改项目风险、问题、需求项目经理工号和姓名
	private void changeManagercode(String projectcode,String projectmanagercode,String projectmanager) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle("enabled = 1 and projectcode = '{0}'",projectcode);
		List<GpmProjectProblemEntity> gpmProjectProblemEntityList = gpmProjectProblemService.queryByWhere(sql.toString());
		List<GpmProjectRiskEntity> gpmProjectRiskEntityList = gpmProjectRiskService.queryByWhere(sql.toString());
		List<GpmProjectReviewEntity> gpmProjectReviewEntityList = gpmProjectReviewService.queryByWhere(sql.toString());
		// 修改项目问题项目经理工号和姓名
		List<BasicEntity> problemBasicEntityList = new ArrayList<>();
		for(GpmProjectProblemEntity gpmProjectProblemEntity : gpmProjectProblemEntityList) {
			gpmProjectProblemEntity.setProjectmanagercode(projectmanagercode);
			gpmProjectProblemEntity.setProjectmanager(projectmanager);
			problemBasicEntityList.add(gpmProjectProblemEntity);
		}
		gpmProjectProblemService.updateBatch(problemBasicEntityList);
		// 修改项目风险项目经理工号和姓名
		List<BasicEntity> riskBasicEntityList = new ArrayList<>();
		for(GpmProjectRiskEntity gpmProjectRiskEntity : gpmProjectRiskEntityList) {
			gpmProjectRiskEntity.setProjectmanagercode(projectmanagercode);
			gpmProjectRiskEntity.setProjectmanager(projectmanager);
			riskBasicEntityList.add(gpmProjectRiskEntity);
		}
		gpmProjectRiskService.updateBatch(riskBasicEntityList);
		List<BasicEntity> reviewBasicEntityList = new ArrayList<>();
		for(GpmProjectReviewEntity gpmProjectReviewEntity : gpmProjectReviewEntityList) {
			gpmProjectReviewEntity.setProjectmanager(projectmanager);
			gpmProjectReviewEntity.setProjectmanagercode(projectmanagercode);
			reviewBasicEntityList.add(gpmProjectReviewEntity);
		}
		gpmProjectReviewService.updateBatch(reviewBasicEntityList);
	}

	// 修改项目任命表项目经理姓名、工号字段
	private void changeSdAppointment(String projectcode,String projectmanagercode,String projectmanager) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" update {0} set projectmanager = '{1}', " +
						"projectmanagercode = '{2}' where projectcode = '{3}' ",
				GpmProjectAppointmentEntity.tableName, projectmanager, projectmanagercode,projectcode);
		gpmProjectAppointmentService.selectExecute(sql.toString());
	}
	// 修改项目任命详情表项目经理姓名、工号字段
	private void changeSdTeam(String projectcode,String projectmanagercode,String projectmanager) {
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" update {0} set username = '{1}', " +
						"usercode = '{2}' where projectcode = '{3}' and projectrole = '{4}' ",
				GpmProjectTeamEntity.tableName,projectmanager, projectmanagercode, projectcode, GpmSystemConst.WorkGroupRoleCode.pm);
		gpmProjectTeamService.selectExecute(sql.toString());
	}


	public void dealWithChangeOwnerPermission(List<Map<String, Object>> tempList) {
		if (org.springframework.util.CollectionUtils.isEmpty(tempList)) {
			return;
		}
		// 获取当前用户在那些省份任职 省总，人总， 财总
		String currentUserCode = getSessionUserBean().getUser().getCode();
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" {0} = '{1}'", MmsDeptExtraInfoEntity.FieldCfocode, currentUserCode);
		sql.appendSingle(" or {0} = '{1}'", MmsDeptExtraInfoEntity.FieldProvincemanagercode, currentUserCode);
		List<MmsDeptExtraInfoEntity> deptExtraInfoList = mmsDeptExtraInfoService.queryByWhere(sql.toString());
		Set<String> deptCommonCodeSet = new HashSet<>();
		if (!org.springframework.util.CollectionUtils.isEmpty(deptExtraInfoList)) {
			deptCommonCodeSet.addAll(deptExtraInfoList.stream().map(MmsDeptExtraInfoEntity::getDeptcommoncode).collect(Collectors.toSet()));
		}
		sql.clear();
		sql.appendSingle(" userid = {0} and roleid in (select id from CboRole where code = 'GpmPMOChangeOwner' ) ",getUserBean().getUser().getId());
		List<CboUserRoleEntity> userRoleEntities = cboUserRoleService.queryByWhere(sql.toString());
		int size = userRoleEntities.size();
		// 在该省份任职，则具有修改owner权限
		for (Map<String, Object> map : tempList) {
			String deptCommonCode = ConvertUtil.convertToString(map.get(LtcContractApplyEntity.FieldDeptcommoncode1));
			map.put("changeownerpermission", deptCommonCodeSet.contains(deptCommonCode) || size >0);
		}
	}

	/***
	 * @description: 置顶与取消置顶功能
	 * @param paraMap
	 * @return
	 * @author: jiangtao1
	 * @date: 2022/8/10 10:08
	 * @modify:
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public String changeTop(Map<String, Object> paraMap) {
		String projectcode = paraMap.get("projectcode").toString();
		String type = ConvertUtil.convertToString(paraMap.get("type"));
		String sourcetype = ConvertUtil.convertToString(paraMap.get("sourcetype"));
		String message = "";
		StringBufferProxy sql = new StringBufferProxy();
		if(GpmProjectEntity.tableName.equals(sourcetype) || GpmProjectPlanEntity.tableName.equals(sourcetype) || GpmProjectReviewEntity.tableName.equals(sourcetype)) {
			if("0".equals(type)) {
				sql.appendSingle("update {0} set whethertop = '1', toptime = sysdate where projectcode = '{1}' and enabled = 1",sourcetype,projectcode);
				message = "置顶成功！";
			} else {
				sql.appendSingle("update {0} set whethertop = '0', toptime = null where projectcode = '{1}' and enabled = 1",sourcetype,projectcode);
				message = "取消置顶成功！";
			}
			this.updateExecute(sql.toString());
		} else {
			message = "操作成功！";
		}
		return message;
	}
}
